Optimize pushing collision data for entity on_step

Since this is fixed overhead for every entity, this is important to optimize.
This optimizes one very common case.

before:
  push_collision_move_result [us] _____________ 64512x   3.562

after:
  push_collision_move_result [us] _____________ 72636x   0.831
This commit is contained in:
sfan5 2024-04-23 21:12:31 +02:00
parent 2e89529eef
commit c24a04d246
4 changed files with 65 additions and 15 deletions

@ -97,3 +97,25 @@ function core.encode_png(width, height, data, compression)
return o_encode_png(width, height, data, compression or 6)
end
-- Helper that pushes a collisionMoveResult structure
if core.set_push_moveresult1 then
-- must match CollisionAxis in collision.h
local AXES = {"x", "y", "z"}
-- <=> script/common/c_content.cpp push_collision_move_result()
core.set_push_moveresult1(function(b0, b1, b2, axis, npx, npy, npz, v0x, v0y, v0z, v1x, v1y, v1z)
return {
touching_ground = b0,
collides = b1,
standing_on_object = b2,
collisions = {{
type = "node",
axis = AXES[axis],
node_pos = vector.new(npx, npy, npz),
old_velocity = vector.new(v0x, v0y, v0z),
new_velocity = vector.new(v1x, v1y, v1z),
}},
}
end)
core.set_push_moveresult1 = nil
end

@ -2480,6 +2480,27 @@ static const char *collision_axis_str[] = {
void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
{
// use faster Lua helper if possible
if (res.collisions.size() == 1 && res.collisions.front().type == COLLISION_NODE) {
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_MOVERESULT1);
const auto &c = res.collisions.front();
lua_pushboolean(L, res.touching_ground);
lua_pushboolean(L, res.collides);
lua_pushboolean(L, res.standing_on_object);
assert(c.axis != COLLISION_AXIS_NONE);
lua_pushinteger(L, static_cast<int>(c.axis));
lua_pushinteger(L, c.node_p.X);
lua_pushinteger(L, c.node_p.Y);
lua_pushinteger(L, c.node_p.Z);
for (v3f v : {c.old_speed / BS, c.new_speed / BS}) {
lua_pushnumber(L, v.X);
lua_pushnumber(L, v.Y);
lua_pushnumber(L, v.Z);
}
lua_call(L, 3 + 1 + 3 + 3 * 2, 1);
return;
}
lua_createtable(L, 0, 4);
setboolfield(L, -1, "touching_ground", res.touching_ground);

@ -58,12 +58,13 @@ enum {
CUSTOM_RIDX_HTTP_API_LUA,
CUSTOM_RIDX_METATABLE_MAP,
// The following four functions are implemented in Lua because LuaJIT can
// The following functions are implemented in Lua because LuaJIT can
// trace them and optimize tables/string better than from the C API.
CUSTOM_RIDX_READ_VECTOR,
CUSTOM_RIDX_PUSH_VECTOR,
CUSTOM_RIDX_READ_NODE,
CUSTOM_RIDX_PUSH_NODE,
CUSTOM_RIDX_PUSH_MOVERESULT1,
};

@ -141,6 +141,11 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
return 0;
});
lua_setfield(m_luastack, -2, "set_push_node");
lua_pushcfunction(m_luastack, [](lua_State *L) -> int {
lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_MOVERESULT1);
return 0;
});
lua_setfield(m_luastack, -2, "set_push_moveresult1");
// Finally, put the table into the global environment:
lua_setglobal(m_luastack, "core");
@ -195,29 +200,30 @@ void ScriptApiBase::clientOpenLibs(lua_State *L)
}
#endif
#define CHECK(ridx, name) do { \
lua_rawgeti(L, LUA_REGISTRYINDEX, ridx); \
FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing " name); \
lua_pop(L, 1); \
} while (0)
void ScriptApiBase::checkSetByBuiltin()
{
lua_State *L = getStack();
if (m_gamedef) {
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_VECTOR);
FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing read_vector");
lua_pop(L, 1);
CHECK(CUSTOM_RIDX_READ_VECTOR, "read_vector");
CHECK(CUSTOM_RIDX_PUSH_VECTOR, "push_vector");
CHECK(CUSTOM_RIDX_READ_NODE, "read_node");
CHECK(CUSTOM_RIDX_PUSH_NODE, "push_node");
}
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_VECTOR);
FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing push_vector");
lua_pop(L, 1);
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_NODE);
FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing read_node");
lua_pop(L, 1);
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_NODE);
FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing push_node");
lua_pop(L, 1);
if (getType() == ScriptingType::Server) {
CHECK(CUSTOM_RIDX_PUSH_MOVERESULT1, "push_moveresult1");
}
}
#undef CHECK
std::string ScriptApiBase::getCurrentModNameInsecure(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);