diff --git a/builtin/game/misc_s.lua b/builtin/game/misc_s.lua index af4002bf2..18812131a 100644 --- a/builtin/game/misc_s.lua +++ b/builtin/game/misc_s.lua @@ -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 diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index de4f2fe02..f63893ff2 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -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(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); diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h index 78ce48e7e..a67b0dad9 100644 --- a/src/script/common/c_internal.h +++ b/src/script/common/c_internal.h @@ -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, }; diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index 7731de7a7..e9907f304 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -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);