Skip to content

Commit

Permalink
Optimize pushing collision data for entity on_step
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sfan5 committed May 2, 2024
1 parent a2bdbeb commit d709941
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 15 deletions.
22 changes: 22 additions & 0 deletions builtin/game/misc_s.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
21 changes: 21 additions & 0 deletions src/script/common/c_content.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/script/common/c_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};


Expand Down
34 changes: 20 additions & 14 deletions src/script/cpp_api/s_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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);

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);
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_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);
Expand Down

0 comments on commit d709941

Please sign in to comment.