58 lines
3.1 KiB
Python
58 lines
3.1 KiB
Python
"""Check production local spline splitting against native MoveSpline validation."""
|
|
from pathlib import Path
|
|
import subprocess,tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
s=(root/'src/server/game/World/ClientlessTravelMgr.cpp').read_text()
|
|
a=s.index(' std::vector<Position> spline;');b=s.index(' if (spline.size() < 2)',a)
|
|
build=s[a:b]
|
|
n=(root/'src/server/game/Movement/Spline/MoveSpline.cpp').read_text()
|
|
a=n.index('bool MoveSplineInitArgs::_checkPathLengths()');b=n.index('\n/// ===',a);native=n[a:b]
|
|
code=r'''
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <random>
|
|
#include <vector>
|
|
using uint32=uint32_t;
|
|
constexpr float MAX_LOCAL_SPLINE_LENGTH=45;
|
|
struct Vector3{
|
|
float x=0,y=0,z=0;
|
|
Vector3 operator-(Vector3 b)const{return {x-b.x,y-b.y,z-b.z};}
|
|
Vector3 operator+(Vector3 b)const{return {x+b.x,y+b.y,z+b.z};}
|
|
Vector3 operator/(float f)const{return {x/f,y/f,z/f};}
|
|
float length()const{return std::hypot(std::hypot(x,y),z);}
|
|
};
|
|
struct Position:Vector3{
|
|
void Relocate(float a,float b,float c,float){x=a;y=b;z=c;}
|
|
float GetPositionX()const{return x;}float GetPositionY()const{return y;}float GetPositionZ()const{return z;}
|
|
};
|
|
struct Player{float GetPositionX(){return 0;}float GetPositionY(){return 0;}float GetPositionZ(){return 0;}float GetOrientation(){return 0;}};
|
|
float Distance3D(float ax,float ay,float az,float bx,float by,float bz){return (Vector3{ax,ay,az}-Vector3{bx,by,bz}).length();}
|
|
struct MoveSplineInitArgs{std::vector<Vector3>path;struct{bool UncompressedPath=false;}flags;bool _checkPathLengths();};
|
|
'''+native+'\nstd::vector<Position> Build(Player* player,std::vector<Vector3> const& points){\n'+build+'\nreturn spline;\n}\n'+r'''
|
|
void check(std::vector<Position> const& p){
|
|
assert(p.size()>=2);MoveSplineInitArgs native;float length=0;
|
|
for(auto v:p)native.path.push_back({v.x,v.y,v.z});
|
|
assert(native._checkPathLengths());
|
|
for(std::size_t i=1;i<p.size();++i){float d=(p[i]-p[i-1]).length();assert(d>=0.1f);length+=d;}
|
|
assert(length<=45.001f);
|
|
}
|
|
int main(){
|
|
Player p;
|
|
// Native validation really rejects the old tiny clipped remainder.
|
|
MoveSplineInitArgs bad;bad.path={{0,0,0},{44.95f,0,0},{45,0,0}};assert(!bad._checkPathLengths());
|
|
auto clipped=Build(&p,{{0,0,0},{4,0,0},{20,0,0},{44.95f,0,0},{49,0,0}});
|
|
check(clipped);assert(clipped.back().x==44.95f);
|
|
auto tiny=Build(&p,{{0,0,0},{1,0,0},{1.06f,0,0},{2,0,0}});check(tiny);assert(tiny.size()==3);
|
|
auto normal=Build(&p,{{0,0,0},{10,0,0},{30,0,0},{50,0,0}});check(normal);assert(normal.back().x==45);
|
|
std::mt19937 rng(26);std::uniform_real_distribution<float> step(0.001f,5);
|
|
for(int trial=0;trial<1000;++trial){std::vector<Vector3> points{{0,0,0}};float x=0;for(int i=0;i<60;++i){x+=step(rng);points.push_back({x,0,0});}check(Build(&p,points));}
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory(prefix='vcore-spline-split-') as folder:
|
|
cpp=Path(folder)/'test.cpp';binary=Path(folder)/'test';cpp.write_text(code)
|
|
subprocess.run(['c++','-std=c++17',str(cpp),'-o',str(binary)],check=True)
|
|
subprocess.run([str(binary)],check=True)
|
|
print('Production local spline clipping passes native path-length validation, tiny remainders and 1000 sampled paths.')
|