Implemented tangible.find. Octrees are more or less done! Yay!
This commit is contained in:
@@ -260,6 +260,9 @@ public:
|
||||
// It is only relevant during the scan.
|
||||
const PlaneScan *scan_config_;
|
||||
IdVector *scan_result_;
|
||||
util::XYZ scan_lo_;
|
||||
util::XYZ scan_hi_;
|
||||
util::XYZ scan_invradius_;
|
||||
int scan_bbxlo_[9], scan_bbxhi_[9];
|
||||
int scan_bbylo_[9], scan_bbyhi_[9];
|
||||
int scan_bbzlo_[9], scan_bbzhi_[9];
|
||||
@@ -462,10 +465,32 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void calculate_search_bboxes(const PlaneScan &scan) {
|
||||
// The final filtering step sometimes uses the inverse of the
|
||||
// radius. In the case that the radius is 0, we want to use a huge
|
||||
// number for the inverse radius, but not infinity, because using infinity
|
||||
// would result in the final filtering step calculating (inf*0).
|
||||
// In the case that the radius is infinite, we want to use zero for the
|
||||
// inverse radius.
|
||||
static float inverse_radius(float f) {
|
||||
if (f == 0) return std::numeric_limits<float>::max();
|
||||
if (std::isinf(f)) return 0;
|
||||
return 1.0f / f;
|
||||
}
|
||||
|
||||
// Given a PlaneScan, calculate the search bboxes,
|
||||
// and all the other related configuration data.
|
||||
void calculate_search_bboxes(const PlaneScan &sc) {
|
||||
scan_config_ = ≻
|
||||
scan_lo_ = sc.center_ - sc.radius_;
|
||||
scan_hi_ = sc.center_ + sc.radius_;
|
||||
|
||||
scan_invradius_.x = inverse_radius(sc.radius_.x);
|
||||
scan_invradius_.y = inverse_radius(sc.radius_.y);
|
||||
scan_invradius_.z = inverse_radius(sc.radius_.z);
|
||||
|
||||
// Convert the scan's bounding box to integral coordinates.
|
||||
NodeInfo bblo(scale_, scan.lo_.x, scan.lo_.y, scan.lo_.z);
|
||||
NodeInfo bbhi(scale_, scan.hi_.x, scan.hi_.y, scan.hi_.z);
|
||||
NodeInfo bblo(scale_, scan_lo_.x, scan_lo_.y, scan_lo_.z);
|
||||
NodeInfo bbhi(scale_, scan_hi_.x, scan_hi_.y, scan_hi_.z);
|
||||
|
||||
// Calculate the bounding box at each level of the tree.
|
||||
NodeID ibblo = bblo.node;
|
||||
@@ -503,37 +528,37 @@ public:
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static inline void scan_push_id(int64_t id, int64_t special, IdVector *result) {
|
||||
if (id != special) {
|
||||
static inline void scan_push_id(int64_t id, int64_t near, IdVector *result) {
|
||||
if (id != near) {
|
||||
result->push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_planeitem(PlaneItem *pi, const PlaneScan &scan, IdVector *result) {
|
||||
switch (scan.shape_) {
|
||||
void scan_planeitem(PlaneItem *pi) {
|
||||
switch (scan_config_->shape_) {
|
||||
case PlaneScan::BOX: {
|
||||
if ((pi->x() >= scan.lo_.x) && (pi->x() <= scan.hi_.x) &&
|
||||
(pi->y() >= scan.lo_.y) && (pi->y() <= scan.hi_.y) &&
|
||||
(pi->z() >= scan.lo_.z) && (pi->z() <= scan.hi_.z)) {
|
||||
scan_push_id(pi->id(), scan.special_, result);
|
||||
if ((pi->x() >= scan_lo_.x) && (pi->x() <= scan_hi_.x) &&
|
||||
(pi->y() >= scan_lo_.y) && (pi->y() <= scan_hi_.y) &&
|
||||
(pi->z() >= scan_lo_.z) && (pi->z() <= scan_hi_.z)) {
|
||||
scan_push_id(pi->id(), scan_config_->near_, scan_result_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PlaneScan::SPHERE: {
|
||||
float dx = (pi->x() - scan.center_.x) * scan.invradius_.x;
|
||||
float dy = (pi->y() - scan.center_.y) * scan.invradius_.y;
|
||||
float dz = (pi->z() - scan.center_.z) * scan.invradius_.z;
|
||||
float dx = (pi->x() - scan_config_->center_.x) * scan_invradius_.x;
|
||||
float dy = (pi->y() - scan_config_->center_.y) * scan_invradius_.y;
|
||||
float dz = (pi->z() - scan_config_->center_.z) * scan_invradius_.z;
|
||||
if (dx*dx + dy*dy + dz*dz <= 1.0) {
|
||||
scan_push_id(pi->id(), scan.special_, result);
|
||||
scan_push_id(pi->id(), scan_config_->near_, scan_result_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PlaneScan::CYLINDER: {
|
||||
if ((pi->z() >= scan.lo_.z) && (pi->z() <= scan.hi_.z)) {
|
||||
float dx = (pi->x() - scan.center_.x) * scan.invradius_.x;
|
||||
float dy = (pi->y() - scan.center_.y) * scan.invradius_.y;
|
||||
if ((pi->z() >= scan_lo_.z) && (pi->z() <= scan_hi_.z)) {
|
||||
float dx = (pi->x() - scan_config_->center_.x) * scan_invradius_.x;
|
||||
float dy = (pi->y() - scan_config_->center_.y) * scan_invradius_.y;
|
||||
if (dx*dx + dy*dy <= 1.0) {
|
||||
scan_push_id(pi->id(), scan.special_, result);
|
||||
scan_push_id(pi->id(), scan_config_->near_, scan_result_);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -557,7 +582,7 @@ public:
|
||||
PlaneItem *pi = first;
|
||||
while (true) {
|
||||
PlaneItem *next = pi->next_;
|
||||
scan_planeitem(pi, *scan_config_, scan_result_);
|
||||
scan_planeitem(pi);
|
||||
if (next == first) break;
|
||||
pi = next;
|
||||
}
|
||||
@@ -595,9 +620,8 @@ public:
|
||||
|
||||
// Scan a planetree.
|
||||
void scan(const PlaneScan &sc, IdVector *result, std::ostream *debug) {
|
||||
scan_config_ = ≻
|
||||
scan_result_ = result;
|
||||
calculate_search_bboxes(sc);
|
||||
scan_result_ = result;
|
||||
|
||||
// We must only call 'scan_node' on nodes that actually exist.
|
||||
// So we check if the tree is empty, and if so, we don't scan the
|
||||
@@ -758,9 +782,9 @@ PlaneMap::~PlaneMap() {}
|
||||
IdVector PlaneMap::scan(const PlaneScan &sc) const {
|
||||
IdVector result;
|
||||
int startpos = 0;
|
||||
if (sc.special_ != 0) {
|
||||
if (!sc.omit_special_) {
|
||||
result.push_back(sc.special_);
|
||||
if (sc.near_ != 0) {
|
||||
if (sc.include_near_) {
|
||||
result.push_back(sc.near_);
|
||||
startpos = 1;
|
||||
}
|
||||
}
|
||||
@@ -789,12 +813,12 @@ eng::string PlaneMap::outliers_debug_string(const eng::string &plane) {
|
||||
return PlaneTree::get(this, plane)->outliers_debug_string();
|
||||
}
|
||||
|
||||
eng::string PlaneMap::search_bboxes_debug_string(const eng::string &plane, const PlaneScan &scan) {
|
||||
return PlaneTree::get(this, plane)->search_bboxes_debug_string(scan);
|
||||
eng::string PlaneMap::search_bboxes_debug_string(const PlaneScan &scan) {
|
||||
return PlaneTree::get(this, scan.plane_)->search_bboxes_debug_string(scan);
|
||||
}
|
||||
|
||||
eng::string PlaneMap::scan_steps_debug_string(const eng::string &plane, const PlaneScan &scan) {
|
||||
return PlaneTree::get(this, plane)->scan_steps_debug_string(scan);
|
||||
eng::string PlaneMap::scan_steps_debug_string(const PlaneScan &scan) {
|
||||
return PlaneTree::get(this, scan.plane_)->scan_steps_debug_string(scan);
|
||||
}
|
||||
|
||||
void PlaneMap::untrack_all() {
|
||||
@@ -803,12 +827,188 @@ void PlaneMap::untrack_all() {
|
||||
}
|
||||
}
|
||||
|
||||
static eng::string tdb(PlaneMap &pm) {
|
||||
return pm.tree_debug_string("p");
|
||||
eng::string PlaneScan::configure(const LuaStack &LS0, LuaSlot config) {
|
||||
LuaVar val, vx, vy, vz;
|
||||
LuaStack LS(LS0.state(), val, vx, vy, vz);
|
||||
|
||||
if (!LS.istable(config)) {
|
||||
return "scan configuration is not a table";
|
||||
}
|
||||
|
||||
static eng::string odb(PlaneMap &pm) {
|
||||
return pm.outliers_debug_string("p");
|
||||
bool have_plane = false;
|
||||
bool have_center = false;
|
||||
bool have_radius = false;
|
||||
bool have_shape = false;
|
||||
bool have_near = false;
|
||||
int parameters = 0;
|
||||
|
||||
LS.rawget(val, config, "plane");
|
||||
if (!LS.isnil(val)) {
|
||||
if (!LS.isstring(val)) {
|
||||
return "scan configuration: 'plane' must be a string";
|
||||
}
|
||||
plane_ = LS.ckstring(val);
|
||||
have_plane = true;
|
||||
parameters += 1;
|
||||
}
|
||||
|
||||
LS.rawget(vx, config, "centerx");
|
||||
LS.rawget(vy, config, "centery");
|
||||
LS.rawget(vz, config, "centerz");
|
||||
if ((!LS.isnil(vx)) || (!LS.isnil(vy)) || (!LS.isnil(vz))) {
|
||||
if (!LS.isnumber(vx)) {
|
||||
return "scan configuration: 'centerx' must be a number";
|
||||
}
|
||||
if (!LS.isnumber(vy)) {
|
||||
return "scan configuration: 'centery' must be a number";
|
||||
}
|
||||
if (!LS.isnumber(vz)) {
|
||||
return "scan configuration: 'centerz' must be a number";
|
||||
}
|
||||
center_.x = LS.cknumber(vx);
|
||||
center_.y = LS.cknumber(vy);
|
||||
center_.z = LS.cknumber(vz);
|
||||
have_center = true;
|
||||
parameters += 3;
|
||||
}
|
||||
|
||||
LS.rawget(val, config, "radius");
|
||||
if (!LS.isnil(val)) {
|
||||
if (!LS.isnumber(val)) {
|
||||
return "scan configuration: 'radius' must be a number";
|
||||
}
|
||||
radius_.x = LS.cknumber(val);
|
||||
radius_.y = radius_.z = radius_.x;
|
||||
have_radius = true;
|
||||
parameters += 1;
|
||||
}
|
||||
|
||||
LS.rawget(vx, config, "radiusx");
|
||||
LS.rawget(vy, config, "radiusy");
|
||||
LS.rawget(vz, config, "radiusz");
|
||||
if ((!LS.isnil(vx)) || (!LS.isnil(vy)) || (!LS.isnil(vz))) {
|
||||
if (!LS.isnumber(vx)) {
|
||||
return "scan configuration: 'radiusx' must be a number";
|
||||
}
|
||||
if (!LS.isnumber(vy)) {
|
||||
return "scan configuration: 'radiusy' must be a number";
|
||||
}
|
||||
if (!LS.isnumber(vz)) {
|
||||
return "scan configuration: 'radiusz' must be a number";
|
||||
}
|
||||
if (have_radius) {
|
||||
return "scan configuration: specified both 'radius' and 'radiusx'";
|
||||
}
|
||||
radius_.x = LS.cknumber(vx);
|
||||
radius_.y = LS.cknumber(vy);
|
||||
radius_.z = LS.cknumber(vz);
|
||||
have_radius = true;
|
||||
parameters += 3;
|
||||
}
|
||||
|
||||
LS.rawget(val, config, "shape");
|
||||
if (!LS.isnil(val)) {
|
||||
if (!LS.isstring(val)) {
|
||||
return "scan configuration: 'shape' must be a string";
|
||||
}
|
||||
eng::string shape = LS.ckstring(val);
|
||||
if (shape == "box") {
|
||||
shape_ = BOX;
|
||||
} else if (shape == "sphere") {
|
||||
shape_ = SPHERE;
|
||||
} else if (shape == "cylinder") {
|
||||
shape_ = CYLINDER;
|
||||
} else {
|
||||
return util::ss("scan configuration: unknown shape ", shape);
|
||||
}
|
||||
have_shape = true;
|
||||
parameters += 1;
|
||||
}
|
||||
|
||||
LS.rawget(val, config, "near");
|
||||
if (!LS.isnil(val)) {
|
||||
int64_t id = LS.tanid(val);
|
||||
if (id == 0) {
|
||||
return "scan configuration: 'near' must be a tangible";
|
||||
}
|
||||
if (have_center) {
|
||||
return "scan configuration: specified both 'center' and 'near'";
|
||||
}
|
||||
if (have_plane) {
|
||||
return "scan configuration: specified both 'plane' and 'near'";
|
||||
}
|
||||
near_ = id;
|
||||
have_center = true;
|
||||
have_plane = true;
|
||||
have_near = true;
|
||||
parameters += 1;
|
||||
}
|
||||
|
||||
LS.rawget(val, config, "include");
|
||||
if (!LS.isnil(val)) {
|
||||
if (!LS.isboolean(val)) {
|
||||
return "scan configuration: 'include' must be a boolean";
|
||||
}
|
||||
if (!have_near) {
|
||||
return "scan configuration: 'include' specified without 'near'";
|
||||
}
|
||||
include_near_ = LS.ckboolean(val);
|
||||
parameters += 1;
|
||||
}
|
||||
|
||||
LS.rawget(val, config, "wholeplane");
|
||||
if (!LS.isnil(val)) {
|
||||
if (!LS.isstring(val)) {
|
||||
return "scan configuration: 'wholeplane' must be a string";
|
||||
}
|
||||
if (have_plane || have_center || have_radius || have_shape) {
|
||||
return "scan configuration: do not specify plane, center, shape, or radius with 'wholeplane'";
|
||||
}
|
||||
plane_ = LS.ckstring(val);
|
||||
set_whole_plane();
|
||||
have_plane = true;
|
||||
have_center = true;
|
||||
have_radius = true;
|
||||
have_shape = true;
|
||||
parameters += 1;
|
||||
}
|
||||
|
||||
if (lua_nkeys(LS.state(), config.index()) != parameters) {
|
||||
return "scan configuration: unrecognized parameters in table";
|
||||
}
|
||||
|
||||
if (!have_plane) {
|
||||
return "scan configuration: did not specify plane";
|
||||
}
|
||||
if (!have_radius) {
|
||||
return "scan configuration: did not specify radius";
|
||||
}
|
||||
if (!have_center) {
|
||||
return "scan configuration: did not specify center";
|
||||
}
|
||||
if (!have_shape) {
|
||||
shape_ = SPHERE; // default value.
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
eng::string PlaneScan::debug_string() const {
|
||||
eng::ostringstream oss;
|
||||
oss << "plane:" << plane_ << " center:" << center_ << " radius:" << radius_;
|
||||
if (shape_ == BOX) oss << " shape:box";
|
||||
else if (shape_ == SPHERE) oss << " shape:sphere";
|
||||
else if (shape_ == CYLINDER) oss << " shape:cylinder";
|
||||
else oss << " shape:unknown";
|
||||
if (near_ != 0) {
|
||||
oss << " near:" << near_ << " include:" << include_near_;
|
||||
}
|
||||
if (omit_nowhere_) {
|
||||
oss << " omit_nowhere:true";
|
||||
}
|
||||
if (!sorted_) {
|
||||
oss << " sorted:false";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// The default radius is set such that float coordinates map directly to
|
||||
@@ -835,7 +1035,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// Test track.
|
||||
pi123.set_pos("p", 0x38, 0x16, 0x87);
|
||||
pi123.track(&pm);
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,8,8"
|
||||
"| L4:80,80,80"
|
||||
@@ -844,14 +1044,14 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Test untrack.
|
||||
pi123.untrack();
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root");
|
||||
|
||||
// Track two items at a time, not in the same cell.
|
||||
pi456.set_pos("p", 0x12, 0x17, 0xAC);
|
||||
pi123.track(&pm);
|
||||
pi456.track(&pm);
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,8,8"
|
||||
"| L4:80,80,80"
|
||||
@@ -862,7 +1062,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move one of the items into the same cell as the other.
|
||||
pi456.set_xyz(0x38, 0x16, 0x87);
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,8,8"
|
||||
"| L4:80,80,80"
|
||||
@@ -871,7 +1071,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 back out of the cell.
|
||||
pi456.set_xyz(0x27, 0x11, 0x31);
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,8,8"
|
||||
"| L4:80,80,80"
|
||||
@@ -882,7 +1082,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 123 to follow 456.
|
||||
pi123.set_xyz(0x27, 0x11, 0x31);
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,8,8"
|
||||
"| L4:80,80,80"
|
||||
@@ -894,8 +1094,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// Move item 456 close to, but not quite on the positive edge.
|
||||
pi123.untrack();
|
||||
pi456.set_xyz(0x23, 0x7FFE, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,f,8"
|
||||
"| L4:80,ff,80"
|
||||
@@ -904,8 +1104,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's on the positive edge, but not an outlier.
|
||||
pi456.set_xyz(0x23, 0x7FFF, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,f,8"
|
||||
"| L4:80,ff,80"
|
||||
@@ -914,8 +1114,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's even closer to the positive edge, but not an outlier.
|
||||
pi456.set_xyz(0x23, 0x7FFF + 0.99, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,f,8"
|
||||
"| L4:80,ff,80"
|
||||
@@ -924,8 +1124,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's just barely a positive outlier.
|
||||
pi456.set_xyz(0x23, 0x8000, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,f,8"
|
||||
"| L4:80,ff,80"
|
||||
@@ -934,8 +1134,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's considerably past the positive edge.
|
||||
pi456.set_xyz(0x23, 0x8048, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,f,8"
|
||||
"| L4:80,ff,80"
|
||||
@@ -944,8 +1144,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's way past the positive edge.
|
||||
pi456.set_xyz(0x23, 0x83748, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:0 wayout:1");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:0 wayout:1");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,f,8"
|
||||
"| L4:80,ff,80"
|
||||
@@ -954,8 +1154,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 close to, but not quite on the negative edge.
|
||||
pi456.set_xyz(0x23, -0x7fff, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,0,8"
|
||||
"| L4:80,00,80"
|
||||
@@ -964,8 +1164,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's on the negative edge, but not an outlier.
|
||||
pi456.set_xyz(0x23, -0x7fff - 0.5, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:0 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,0,8"
|
||||
"| L4:80,00,80"
|
||||
@@ -974,8 +1174,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's just barely a negative outlier.
|
||||
pi456.set_xyz(0x23, -0x8000, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,0,8"
|
||||
"| L4:80,00,80"
|
||||
@@ -984,8 +1184,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's significantly past the negative edge.
|
||||
pi456.set_xyz(0x23, -0x8048, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:1 wayout:0");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,0,8"
|
||||
"| L4:80,00,80"
|
||||
@@ -994,8 +1194,8 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
|
||||
// Move item 456 so that it's way past the negative edge.
|
||||
pi456.set_xyz(0x23, -0x83048, 0x27);
|
||||
LuaAssertStrEq(L, odb(pm), "total:1 justout:0 wayout:1");
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.outliers_debug_string("p"), "total:1 justout:0 wayout:1");
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:8,0,8"
|
||||
"| L4:80,00,80"
|
||||
@@ -1005,14 +1205,14 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// Test the calculation of search bboxes.
|
||||
// The two corners are deliberately not in low-high order.
|
||||
scan.clear();
|
||||
scan.set_bbox_given_two_corners(util::XYZ(0x23, 0x97, 0x103),
|
||||
util::XYZ(0x309, 0x412, 0x27));
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string("p", scan),
|
||||
scan.set_plane("p");
|
||||
scan.set_bbox_given_center_radius(util::XYZ(0x23, 0x97, 0x103), 2.0f);
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||
"|Level 8 0,0,0 - 0,0,0"
|
||||
"|Level 6 8,8,8 - 8,8,8"
|
||||
"|Level 4 80,80,80 - 83,84,81"
|
||||
"|Level 2 802,809,802 - 830,841,810"
|
||||
"|Level 0 8023,8097,8027 - 8309,8412,8103");
|
||||
"|Level 4 80,80,81 - 80,80,81"
|
||||
"|Level 2 802,809,810 - 802,809,810"
|
||||
"|Level 0 8021,8095,8101 - 8025,8099,8105");
|
||||
|
||||
// TESTS OF SCANNING
|
||||
|
||||
@@ -1025,8 +1225,9 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// right on the one object. Check the bboxes to make
|
||||
// sure they only include the one cell.
|
||||
scan.clear();
|
||||
scan.set_plane("p");
|
||||
scan.set_bbox_given_center_radius(util::XYZ(0x12, 0x34, 0x45), 0.0);
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||
"|Level 8 0,0,0 - 0,0,0"
|
||||
"|Level 6 8,8,8 - 8,8,8"
|
||||
"|Level 4 80,80,80 - 80,80,80"
|
||||
@@ -1034,7 +1235,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
"|Level 0 8012,8034,8045 - 8012,8034,8045");
|
||||
|
||||
// Run the scan with radius zero. It should find the one object.
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||
"|L8:root"
|
||||
"| L7:2,2,2"
|
||||
"| L6:8,8,8"
|
||||
@@ -1050,8 +1251,9 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// bboxes as before, since a half-unit isn't enough to shift
|
||||
// from one cell to the next.
|
||||
scan.clear();
|
||||
scan.set_plane("p");
|
||||
scan.set_bbox_given_center_radius(util::XYZ(0x12 + 0.5, 0x34, 0x45), 0.0);
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||
"|Level 8 0,0,0 - 0,0,0"
|
||||
"|Level 6 8,8,8 - 8,8,8"
|
||||
"|Level 4 80,80,80 - 80,80,80"
|
||||
@@ -1062,7 +1264,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// from the object. It should encounter the cell containing the
|
||||
// one object, but the object should get removed in the final
|
||||
// filtering step.
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||
"|L8:root"
|
||||
"| L7:2,2,2"
|
||||
"| L6:8,8,8"
|
||||
@@ -1077,8 +1279,9 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// Next, expand the scan radius to huge. Examine the bboxes
|
||||
// to make sure they cover the entire PlaneTree.
|
||||
scan.clear();
|
||||
scan.set_plane("p");
|
||||
scan.set_bbox_given_center_radius(util::XYZ(0x12, 0x34, 0x45), 100000.0);
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||
"|Level 8 0,0,0 - 0,0,0"
|
||||
"|Level 6 0,0,0 - f,f,f"
|
||||
"|Level 4 00,00,00 - ff,ff,ff"
|
||||
@@ -1088,7 +1291,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// Walk the tree using the expansive search bboxes. It should
|
||||
// find the one object, and it should still only traverse the same
|
||||
// cells, because those are the only cells that exist.
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||
"|L8:root"
|
||||
"| L7:2,2,2"
|
||||
"| L6:8,8,8"
|
||||
@@ -1104,7 +1307,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// using the expansive search. It should find both objects.
|
||||
pi456.set_pos("p", 0x14, 0x35, 0x30);
|
||||
pi456.track(&pm);
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||
"|L8:root"
|
||||
"| L7:2,2,2"
|
||||
"| L6:8,8,8"
|
||||
@@ -1120,13 +1323,66 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
"| L0:8012,8034,8045 123"
|
||||
"|Result: 123,456");
|
||||
|
||||
// We're going to test that sphere of radius 0.0 works. This is an important
|
||||
// test because the sphere calculation involves calculating the inverse of
|
||||
// the radius, which has to be special-cased when radius is zero. We need
|
||||
// special-case code for this. In this test case, we set up a scan with two
|
||||
// objects in the same cell, just a smidge apart. Use a sphere scan with
|
||||
// radius zero, centered right on object 123 (but missing object 456).
|
||||
pm.untrack_all();
|
||||
pi123.set_pos("p", 0x12 + 0.1, 0x34, 0x45);
|
||||
pi456.set_pos("p", 0x12 + 0.2, 0x34, 0x45);
|
||||
pi123.track(&pm);
|
||||
pi456.track(&pm);
|
||||
scan.clear();
|
||||
scan.set_plane("p");
|
||||
scan.set_shape(PlaneScan::SPHERE);
|
||||
scan.set_bbox_given_center_radius(util::XYZ(0x12 + 0.1, 0x34, 0x45), 0.0);
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||
"|L8:root"
|
||||
"| L7:2,2,2"
|
||||
"| L6:8,8,8"
|
||||
"| L5:20,20,20"
|
||||
"| L4:80,80,80"
|
||||
"| L3:200,200,201"
|
||||
"| L2:801,803,804"
|
||||
"| L1:2004,200d,2011"
|
||||
"| L0:8012,8034,8045 123,456"
|
||||
"|Result: 123");
|
||||
|
||||
// We're going to test that 'whole plane' searches work.
|
||||
// These use an infinite radius.
|
||||
pm.untrack_all();
|
||||
pi123.set_pos("p", 0x12, 0x34, 0x45);
|
||||
pi123.track(&pm);
|
||||
scan.clear();
|
||||
scan.set_plane("p");
|
||||
scan.set_whole_plane();
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||
"|Level 8 0,0,0 - 0,0,0"
|
||||
"|Level 6 0,0,0 - f,f,f"
|
||||
"|Level 4 00,00,00 - ff,ff,ff"
|
||||
"|Level 2 000,000,000 - fff,fff,fff"
|
||||
"|Level 0 0000,0000,0000 - ffff,ffff,ffff");
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||
"|L8:root"
|
||||
"| L7:2,2,2"
|
||||
"| L6:8,8,8"
|
||||
"| L5:20,20,20"
|
||||
"| L4:80,80,80"
|
||||
"| L3:200,200,201"
|
||||
"| L2:801,803,804"
|
||||
"| L1:2004,200d,2011"
|
||||
"| L0:8012,8034,8045 123"
|
||||
"|Result: 123");
|
||||
|
||||
// Set up a tree with a single object that's outside
|
||||
// the tree's bounding box (an outlier). Print the tree
|
||||
// to verify that the object ended up on the edge.
|
||||
pm.untrack_all();
|
||||
pi123.set_pos("p", 0x100000, 0x16, 0x23);
|
||||
pi123.track(&pm);
|
||||
LuaAssertStrEq(L, tdb(pm),
|
||||
LuaAssertStrEq(L, pm.tree_debug_string("p"),
|
||||
"|L8:root"
|
||||
"| L6:f,8,8"
|
||||
"| L4:ff,80,80"
|
||||
@@ -1138,8 +1394,9 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
// contains the outlier. It also contains a few other cells
|
||||
// because the radius is nonzero.
|
||||
scan.clear();
|
||||
scan.set_plane("p");
|
||||
scan.set_bbox_given_center_radius(util::XYZ(0x100000, 0x16, 0x23), 0.2);
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||
"|Level 8 0,0,0 - 0,0,0"
|
||||
"|Level 6 f,8,8 - f,8,8"
|
||||
"|Level 4 ff,80,80 - ff,80,80"
|
||||
@@ -1147,7 +1404,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
||||
"|Level 0 ffff,8015,8022 - ffff,8016,8023");
|
||||
|
||||
// Confirm that the scan finds the outlier.
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string("p", scan),
|
||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||
"|L8:root"
|
||||
"| L7:3,2,2"
|
||||
"| L6:f,8,8"
|
||||
|
||||
@@ -97,7 +97,7 @@ private:
|
||||
eng::string plane_;
|
||||
|
||||
// The bounding box of the scan.
|
||||
util::XYZ lo_, hi_, center_, invradius_;
|
||||
util::XYZ center_, radius_;
|
||||
|
||||
// If you scan a cylinder or SPHERE, it actually
|
||||
// scans the bounding box first, then clips out
|
||||
@@ -109,10 +109,10 @@ private:
|
||||
// nondeterminism. Scans by lua should always be sorted.
|
||||
bool sorted_;
|
||||
|
||||
// The special ID, if nonzero, is either PREPENDED to the
|
||||
// results, or OMITTED from the results, depending on omit_special.
|
||||
int64_t special_;
|
||||
bool omit_special_;
|
||||
// The near ID, if nonzero, is either PREPENDED to the
|
||||
// results, or OMITTED from the results, depending on include_near_.
|
||||
int64_t near_;
|
||||
bool include_near_;
|
||||
|
||||
// If this is true, items on the nowhere plane are not scanned.
|
||||
bool omit_nowhere_;
|
||||
@@ -122,44 +122,52 @@ public:
|
||||
plane_ = "";
|
||||
shape_ = BOX;
|
||||
sorted_ = true;
|
||||
special_ = 0;
|
||||
omit_special_ = false;
|
||||
near_ = 0;
|
||||
include_near_ = false;
|
||||
omit_nowhere_ = false;
|
||||
lo_ = hi_ = center_ = util::XYZ();
|
||||
radius_ = center_ = util::XYZ();
|
||||
}
|
||||
PlaneScan() { clear(); }
|
||||
|
||||
// Convert a lua table into a scan configuration.
|
||||
void configure(LuaStack &LS, LuaSlot slot);
|
||||
//
|
||||
// If there is an error in the configuration, returns an
|
||||
// error message, otherwise returns empty string.
|
||||
//
|
||||
// Caution: if this detects the configuration flag 'near',
|
||||
// then it stores the near ID. However, it doesn't fetch
|
||||
// the center and plane. It is the caller's responsibility
|
||||
// to check if 'near' has been set, and if so, store a center
|
||||
// and plane. This is admittedly ugly, but it eliminates
|
||||
// a dependency on the world module.
|
||||
//
|
||||
eng::string configure(const LuaStack &LS, LuaSlot slot);
|
||||
|
||||
// Set the bounding box given two corners.
|
||||
void set_bbox_given_two_corners(const util::XYZ &a, const util::XYZ &b) {
|
||||
lo_.x = std::min(a.x, b.x);
|
||||
lo_.y = std::min(a.y, b.y);
|
||||
lo_.z = std::min(a.z, b.z);
|
||||
hi_.x = std::max(a.x, b.x);
|
||||
hi_.y = std::max(a.y, b.y);
|
||||
hi_.z = std::max(a.z, b.z);
|
||||
center_ = (lo_ + hi_) * 0.5;
|
||||
invradius_.x = 2.0 / (hi_.x - lo_.x);
|
||||
invradius_.y = 2.0 / (hi_.y - lo_.y);
|
||||
invradius_.z = 2.0 / (hi_.z - lo_.z);
|
||||
}
|
||||
|
||||
// Set the bounding box given a center and a radius.
|
||||
void set_bbox_given_center_radius(const util::XYZ ¢er, float r) {
|
||||
util::XYZ offset(r, r, r);
|
||||
lo_ = center - offset;
|
||||
hi_ = center + offset;
|
||||
center_ = center;
|
||||
invradius_.x = invradius_.y = invradius_.z = (1.0 / r);
|
||||
set_center(center);
|
||||
set_radius(r);
|
||||
}
|
||||
|
||||
void set_whole_plane() {
|
||||
shape_ = BOX;
|
||||
center_ = util::XYZ();
|
||||
radius_.x = std::numeric_limits<float>::infinity();
|
||||
radius_.y = radius_.z = radius_.x;
|
||||
}
|
||||
|
||||
void set_center(const util::XYZ ¢er) { center_ = center; }
|
||||
void set_radius(const util::XYZ &radius) { radius_ = radius; }
|
||||
void set_radius(float f) { radius_.x = radius_.y = radius_.z = f; }
|
||||
void set_plane(std::string_view p) { plane_ = p; }
|
||||
void set_shape(Shape s) { shape_ = s; }
|
||||
void set_sorted(bool s) { sorted_ = s; }
|
||||
void set_special(int64_t id, bool omit) { special_ = id; omit_special_ = omit; }
|
||||
void set_near(int64_t id, bool inc) { near_ = id; include_near_ = inc; }
|
||||
void set_omit_nowhere(bool b) { omit_nowhere_ = b; }
|
||||
|
||||
int64_t near() const { return near_; }
|
||||
|
||||
// Reveal the contents of the PlaneScan as a string.
|
||||
eng::string debug_string() const;
|
||||
};
|
||||
|
||||
class PlaneItem : public eng::nevernew {
|
||||
@@ -222,8 +230,8 @@ public:
|
||||
// This is for unit testing.
|
||||
eng::string tree_debug_string(const eng::string &plane);
|
||||
eng::string outliers_debug_string(const eng::string &plane);
|
||||
eng::string search_bboxes_debug_string(const eng::string &plane, const PlaneScan &scan);
|
||||
eng::string scan_steps_debug_string(const eng::string &plane, const PlaneScan &scan);
|
||||
eng::string search_bboxes_debug_string(const PlaneScan &scan);
|
||||
eng::string scan_steps_debug_string(const PlaneScan &scan);
|
||||
|
||||
// Untrack all planeitems. This is for unit testing.
|
||||
void untrack_all();
|
||||
|
||||
@@ -407,5 +407,9 @@ inline std::ostream &operator<<(std::ostream &oss, util::FormattedNumber<VALUE>
|
||||
return oss;
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &oss, const util::XYZ &xyz) {
|
||||
oss << xyz.x << "," << xyz.y << "," << xyz.z;
|
||||
return oss;
|
||||
}
|
||||
|
||||
#endif // UTIL_HPP
|
||||
|
||||
@@ -272,7 +272,7 @@ LuaDefine(tangible_near, "tan,radius,omit_nowhere,omit_self",
|
||||
scan.set_bbox_given_center_radius(aqback.xyz(), LS.cknumber(lradius));
|
||||
scan.set_shape(PlaneScan::SPHERE);
|
||||
scan.set_sorted(true);
|
||||
scan.set_special(tan->id(), LS.ckboolean(lomit_self));
|
||||
scan.set_near(tan->id(), !LS.ckboolean(lomit_self));
|
||||
scan.set_omit_nowhere(LS.ckboolean(lomit_nowhere));
|
||||
|
||||
util::IdVector idv = w->plane_map_.scan(scan);
|
||||
@@ -301,6 +301,85 @@ LuaDefine(tangible_scan, "plane,x,y,radius,omit_nowhere",
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(tangible_find, "config",
|
||||
"|Find tangibles by their location."
|
||||
"|"
|
||||
"|There are multiple ways to specify the plane, the bounding"
|
||||
"|box, and the shape of the search. The most basic is to"
|
||||
"|include these parameters in the table:"
|
||||
"|"
|
||||
"| plane : the plane to search (a string)"
|
||||
"| centerx : x-coordinate of the center of the search"
|
||||
"| centery : y-coordinate of the center of the search"
|
||||
"| centerz : z-coordinate of the center of the search"
|
||||
"| radius : the radius of the search"
|
||||
"| shape : 'box', 'sphere', or 'cylinder'"
|
||||
"|"
|
||||
"|Shape has a default: 'sphere'. The other parameters do"
|
||||
"|not have default values."
|
||||
"|"
|
||||
"|Instead of specifying the radius as a single float,"
|
||||
"|you may optionally specify separate radii for each dimension."
|
||||
"|"
|
||||
"| radiusx : the radius in the x-dimension."
|
||||
"| radiusy : the radius in the y-dimension."
|
||||
"| radiusz : the radius in the z-dimension."
|
||||
"|"
|
||||
"|If you specify different radii in each dimension, then the"
|
||||
"|'sphere' shape will actually be a spheroid, and the 'cylinder'"
|
||||
"|shape will actually be a cylindroid."
|
||||
"|"
|
||||
"|Instead of specifying the center and plane, you can specify"
|
||||
"|a tangible to search near:"
|
||||
"|"
|
||||
"| near : a tangible in whose vicinity the search occurs"
|
||||
"|"
|
||||
"|If you specify 'near', then by default, the near tangible is"
|
||||
"|filtered out of the search. If you want to include it in the"
|
||||
"|results, set the 'include' flag to true. In this case, the"
|
||||
"|near tangible will always be the first search result:"
|
||||
"|"
|
||||
"| include : include the 'near' object in the results"
|
||||
"|"
|
||||
"|If you want to search an entire plane, you can use the"
|
||||
"|wholeplane option, which replaces all the other options:"
|
||||
"|"
|
||||
"| wholeplane: the name of the plane to scan in its entirety"
|
||||
"|"
|
||||
"|It is valid to use 0.0 as the radius. If you do so, then only"
|
||||
"|objects at the exact center you specify will be found."
|
||||
"|"
|
||||
"|If you are making a 2D game, it works fine to set all object Z"
|
||||
"|coordinates to zero, and then do searches with centerz=0.0"
|
||||
"|and radiusz=0.0."
|
||||
"|") {
|
||||
LuaArg config;
|
||||
LuaRet result;
|
||||
LuaStack LS(L, config, result);
|
||||
PlaneScan scan;
|
||||
eng::string error = scan.configure(LS, config);
|
||||
if (!error.empty()) {
|
||||
luaL_error(L, "%s", error.c_str());
|
||||
}
|
||||
// When the configure routine sees the 'near' flag, it stores the tangible
|
||||
// ID, but not the center and plane, because doing so would require it to
|
||||
// know about world models. We have to handle center and plane for 'near'
|
||||
// separately.
|
||||
World *w = World::fetch_global_pointer(L);
|
||||
int64_t near = scan.near();
|
||||
if (near != 0) {
|
||||
Tangible *t = w->tangible_get(near);
|
||||
assert(t != nullptr); // Should never happen.
|
||||
const AnimStep &aqback = t->anim_queue_.back();
|
||||
scan.set_plane(aqback.plane());
|
||||
scan.set_center(aqback.xyz());
|
||||
}
|
||||
// Do the scan.
|
||||
util::IdVector idv = w->plane_map_.scan(scan);
|
||||
tangible_getall(LS, result, idv);
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(tangible_start, "tangible,function,arg1,arg2...",
|
||||
"|Start a thread."
|
||||
"|"
|
||||
@@ -471,6 +550,9 @@ LuaDefine(math_random, "(args...)",
|
||||
"| (high) - an int between 1 and high inclusive"
|
||||
"| (low, high) - an int between low and high inclusive"
|
||||
"|"
|
||||
"|You may also pass in a randomstate table"
|
||||
"|as an optional first argument."
|
||||
"|"
|
||||
"|math.random tries to cooperate with predictive"
|
||||
"|reexecution to be as predictable as possible."
|
||||
"|To achieve predictability, we used an ad-hoc"
|
||||
|
||||
@@ -235,7 +235,7 @@ util::IdVector World::get_near(int64_t player_id, float radius, bool exclude_now
|
||||
scan.set_shape(PlaneScan::SPHERE);
|
||||
scan.set_sorted(sorted);
|
||||
scan.set_omit_nowhere(exclude_nowhere);
|
||||
scan.set_special(player_id, omit_player);
|
||||
scan.set_near(player_id, !omit_player);
|
||||
return plane_map_.scan(scan);
|
||||
}
|
||||
|
||||
|
||||
@@ -552,6 +552,7 @@ private:
|
||||
friend int lfn_tangible_nopredict(lua_State *L);
|
||||
friend int lfn_tangible_near(lua_State *L);
|
||||
friend int lfn_tangible_scan(lua_State *L);
|
||||
friend int lfn_tangible_find(lua_State *L);
|
||||
friend int lfn_tangible_start(lua_State *L);
|
||||
friend int lfn_math_random(lua_State *L);
|
||||
friend int lfn_math_randomstate(lua_State *L);
|
||||
|
||||
Reference in New Issue
Block a user