Optimize env access and structs in collisionMoveSimple

This commit is contained in:
sfan5 2024-04-23 20:23:31 +02:00
parent 92d03f3832
commit 2e89529eef

@ -36,45 +36,47 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#warning "-ffast-math is known to cause bugs in collision code, do not use!" #warning "-ffast-math is known to cause bugs in collision code, do not use!"
#endif #endif
namespace {
struct NearbyCollisionInfo { struct NearbyCollisionInfo {
// node // node
NearbyCollisionInfo(bool is_ul, int bouncy, const v3s16 &pos, NearbyCollisionInfo(bool is_ul, int bouncy, v3s16 pos, const aabb3f &box) :
const aabb3f &box) :
is_unloaded(is_ul),
obj(nullptr), obj(nullptr),
bouncy(bouncy), box(box),
position(pos), position(pos),
box(box) bouncy(bouncy),
is_unloaded(is_ul),
is_step_up(false)
{} {}
// object // object
NearbyCollisionInfo(ActiveObject *obj, int bouncy, NearbyCollisionInfo(ActiveObject *obj, int bouncy, const aabb3f &box) :
const aabb3f &box) :
is_unloaded(false),
obj(obj), obj(obj),
box(box),
bouncy(bouncy), bouncy(bouncy),
box(box) is_unloaded(false),
is_step_up(false)
{} {}
inline bool isObject() const { return obj != nullptr; } inline bool isObject() const { return obj != nullptr; }
bool is_unloaded;
bool is_step_up = false;
ActiveObject *obj; ActiveObject *obj;
int bouncy;
v3s16 position;
aabb3f box; aabb3f box;
v3s16 position;
u8 bouncy;
// bitfield to save space
bool is_unloaded:1, is_step_up:1;
}; };
// Helper functions: // Helper functions:
// Truncate floating point numbers to specified number of decimal places // Truncate floating point numbers to specified number of decimal places
// in order to move all the floating point error to one side of the correct value // in order to move all the floating point error to one side of the correct value
static inline f32 truncate(const f32 val, const f32 factor) inline f32 truncate(const f32 val, const f32 factor)
{ {
return truncf(val * factor) / factor; return truncf(val * factor) / factor;
} }
static inline v3f truncate(const v3f& vec, const f32 factor) inline v3f truncate(const v3f vec, const f32 factor)
{ {
return v3f( return v3f(
truncate(vec.X, factor), truncate(vec.X, factor),
@ -83,6 +85,8 @@ static inline v3f truncate(const v3f& vec, const f32 factor)
); );
} }
}
// Helper function: // Helper function:
// Checks for collision of a moving aabbox with a static aabbox // Checks for collision of a moving aabbox with a static aabbox
// Returns -1 if no collision, 0 if X collision, 1 if Y collision, 2 if Z collision // Returns -1 if no collision, 0 if X collision, 1 if Y collision, 2 if Z collision
@ -270,11 +274,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
/* /*
Collect node boxes in movement range Collect node boxes in movement range
*/ */
std::vector<NearbyCollisionInfo> cinfo;
{
//TimeTaker tt2("collisionMoveSimple collect boxes");
ScopeProfiler sp2(g_profiler, PROFILER_NAME("collision collect boxes"), SPT_AVG, PRECISION_MICRO);
// cached allocation
thread_local std::vector<NearbyCollisionInfo> cinfo;
cinfo.clear();
{
v3f minpos_f( v3f minpos_f(
MYMIN(pos_f->X, newpos_f.X), MYMIN(pos_f->X, newpos_f.X),
MYMIN(pos_f->Y, newpos_f.Y) + 0.01f * BS, // bias rounding, player often at +/-n.5 MYMIN(pos_f->Y, newpos_f.Y) + 0.01f * BS, // bias rounding, player often at +/-n.5
@ -288,8 +293,11 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
v3s16 min = floatToInt(minpos_f + box_0.MinEdge, BS) - v3s16(1, 1, 1); v3s16 min = floatToInt(minpos_f + box_0.MinEdge, BS) - v3s16(1, 1, 1);
v3s16 max = floatToInt(maxpos_f + box_0.MaxEdge, BS) + v3s16(1, 1, 1); v3s16 max = floatToInt(maxpos_f + box_0.MaxEdge, BS) + v3s16(1, 1, 1);
const auto *nodedef = gamedef->getNodeDefManager();
bool any_position_valid = false; bool any_position_valid = false;
thread_local std::vector<aabb3f> nodeboxes;
v3s16 p; v3s16 p;
for (p.Z = min.Z; p.Z <= max.Z; p.Z++) for (p.Z = min.Z; p.Z <= max.Z; p.Z++)
for (p.Y = min.Y; p.Y <= max.Y; p.Y++) for (p.Y = min.Y; p.Y <= max.Y; p.Y++)
@ -301,7 +309,6 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
// Object collides into walkable nodes // Object collides into walkable nodes
any_position_valid = true; any_position_valid = true;
const NodeDefManager *nodedef = gamedef->getNodeDefManager();
const ContentFeatures &f = nodedef->get(n); const ContentFeatures &f = nodedef->get(n);
if (!f.walkable) if (!f.walkable)
@ -310,36 +317,10 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
// Negative bouncy may have a meaning, but we need +value here. // Negative bouncy may have a meaning, but we need +value here.
int n_bouncy_value = abs(itemgroup_get(f.groups, "bouncy")); int n_bouncy_value = abs(itemgroup_get(f.groups, "bouncy"));
int neighbors = 0; u8 neighbors = n.getNeighbors(p, map);
if (f.drawtype == NDT_NODEBOX &&
f.node_box.type == NODEBOX_CONNECTED) {
v3s16 p2 = p;
p2.Y++; nodeboxes.clear();
getNeighborConnectingFace(p2, nodedef, map, n, 1, &neighbors); n.getCollisionBoxes(nodedef, &nodeboxes, neighbors);
p2 = p;
p2.Y--;
getNeighborConnectingFace(p2, nodedef, map, n, 2, &neighbors);
p2 = p;
p2.Z--;
getNeighborConnectingFace(p2, nodedef, map, n, 4, &neighbors);
p2 = p;
p2.X--;
getNeighborConnectingFace(p2, nodedef, map, n, 8, &neighbors);
p2 = p;
p2.Z++;
getNeighborConnectingFace(p2, nodedef, map, n, 16, &neighbors);
p2 = p;
p2.X++;
getNeighborConnectingFace(p2, nodedef, map, n, 32, &neighbors);
}
std::vector<aabb3f> nodeboxes;
n.getCollisionBoxes(gamedef->ndef(), &nodeboxes, neighbors);
// Calculate float position only once // Calculate float position only once
v3f posf = intToFloat(p, BS); v3f posf = intToFloat(p, BS);
@ -365,19 +346,28 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
return result; return result;
} }
} // tt2 }
if(collideWithObjects) /*
{ Collect object boxes in movement range
/* add object boxes to cinfo */ */
auto process_object = [] (ActiveObject *object) {
if (object && object->collideWithObjects()) {
aabb3f box;
if (object->getCollisionBox(&box))
cinfo.emplace_back(object, 0, box);
}
};
if (collideWithObjects) {
// Calculate distance by speed, add own extent and 1.5m of tolerance
const f32 distance = speed_f->getLength() * dtime +
box_0.getExtent().getLength() + 1.5f * BS;
std::vector<ActiveObject*> objects;
#ifndef SERVER #ifndef SERVER
ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env); ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env);
if (c_env != 0) { if (c_env) {
// Calculate distance by speed, add own extent and 1.5m of tolerance
f32 distance = speed_f->getLength() * dtime +
box_0.getExtent().getLength() + 1.5f * BS;
std::vector<DistanceSortedActiveObject> clientobjects; std::vector<DistanceSortedActiveObject> clientobjects;
c_env->getActiveObjects(*pos_f, distance, clientobjects); c_env->getActiveObjects(*pos_f, distance, clientobjects);
@ -385,58 +375,40 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
// Do collide with everything but itself and the parent CAO // Do collide with everything but itself and the parent CAO
if (!self || (self != clientobject.obj && if (!self || (self != clientobject.obj &&
self != clientobject.obj->getParent())) { self != clientobject.obj->getParent())) {
objects.push_back((ActiveObject*) clientobject.obj); process_object(clientobject.obj);
} }
} }
}
else
#endif
{
if (s_env != NULL) {
// Calculate distance by speed, add own extent and 1.5m of tolerance
f32 distance = speed_f->getLength() * dtime +
box_0.getExtent().getLength() + 1.5f * BS;
// search for objects which are not us, or we are not its parent // add collision with local player
// we directly use the callback to populate the result to prevent
// a useless result loop here
auto include_obj_cb = [self, &objects] (ServerActiveObject *obj) {
if (!obj->isGone() &&
(!self || (self != obj && self != obj->getParent()))) {
objects.push_back((ActiveObject *)obj);
}
return false;
};
std::vector<ServerActiveObject *> s_objects;
s_env->getObjectsInsideRadius(s_objects, *pos_f, distance, include_obj_cb);
}
}
for (std::vector<ActiveObject*>::const_iterator iter = objects.begin();
iter != objects.end(); ++iter) {
ActiveObject *object = *iter;
if (object && object->collideWithObjects()) {
aabb3f object_collisionbox;
if (object->getCollisionBox(&object_collisionbox))
cinfo.emplace_back(object, 0, object_collisionbox);
}
}
#ifndef SERVER
if (self && c_env) {
LocalPlayer *lplayer = c_env->getLocalPlayer(); LocalPlayer *lplayer = c_env->getLocalPlayer();
if (lplayer->getParent() == nullptr) { if (lplayer->getParent() == nullptr) {
aabb3f lplayer_collisionbox = lplayer->getCollisionbox(); aabb3f lplayer_collisionbox = lplayer->getCollisionbox();
v3f lplayer_pos = lplayer->getPosition(); v3f lplayer_pos = lplayer->getPosition();
lplayer_collisionbox.MinEdge += lplayer_pos; lplayer_collisionbox.MinEdge += lplayer_pos;
lplayer_collisionbox.MaxEdge += lplayer_pos; lplayer_collisionbox.MaxEdge += lplayer_pos;
ActiveObject *obj = (ActiveObject*) lplayer->getCAO(); auto *obj = (ActiveObject*) lplayer->getCAO();
cinfo.emplace_back(obj, 0, lplayer_collisionbox); cinfo.emplace_back(obj, 0, lplayer_collisionbox);
} }
} }
else
#endif #endif
} //tt3 if (s_env) {
// search for objects which are not us, or we are not its parent.
// we directly process the object in this callback to avoid useless
// looping afterwards.
auto include_obj_cb = [self, &process_object] (ServerActiveObject *obj) {
if (!obj->isGone() &&
(!self || (self != obj && self != obj->getParent()))) {
process_object(obj);
}
return false;
};
// nothing is put into this vector
std::vector<ServerActiveObject*> s_objects;
s_env->getObjectsInsideRadius(s_objects, *pos_f, distance, include_obj_cb);
}
}
/* /*
Collision detection Collision detection
@ -572,7 +544,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
if (is_collision) { if (is_collision) {
info.axis = nearest_collided; info.axis = nearest_collided;
result.collisions.push_back(info); result.collisions.push_back(std::move(info));
} }
} }
} }