ソースを参照

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
sfan5 6 ヶ月 前
コミット
c24a04d246

+ 22 - 0
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

+ 21 - 0
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<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);

+ 2 - 1
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,
 };
 
 

+ 20 - 14
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);
-
-		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);