From 5ebb4237e204bfa760313f6f2a46a09dceb9cce0 Mon Sep 17 00:00:00 2001
From: Elia Argentieri <elia.argentieri@openmailbox.org>
Date: Thu, 25 Jun 2015 14:57:10 +0200
Subject: [PATCH] Added get_player_velocity() method. Fixes #1176

---
 doc/lua_api.txt                 |   1 +
 src/script/lua_api/l_object.cpp | 160 ++++++++++++++++++--------------
 src/script/lua_api/l_object.h   |   3 +
 3 files changed, 92 insertions(+), 72 deletions(-)

diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 34d22cdb8..e156d75e4 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -2470,6 +2470,7 @@ This is basically a reference to a C++ `ServerActiveObject`
 
 ##### Player-only (no-op for other objects)
 * `get_player_name()`: returns `""` if is not a player
+* `get_player_velocity()`: returns `nil` if is not a player otherwise a table {x, y, z} representing the player's instantaneous velocity in nodes/s
 * `get_look_dir()`: get camera direction as a unit vector
 * `get_look_pitch()`: pitch in radians
 * `get_look_yaw()`: yaw in radians (wraps around pretty randomly as of now)
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index 96fb0c579..fca69b996 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -80,7 +80,7 @@ ObjectRef* ObjectRef::checkobject(lua_State *L, int narg)
 {
 	luaL_checktype(L, narg, LUA_TUSERDATA);
 	void *ud = luaL_checkudata(L, narg, className);
-	if(!ud) luaL_typerror(L, narg, className);
+	if (!ud) luaL_typerror(L, narg, className);
 	return *(ObjectRef**)ud;  // unbox pointer
 }
 
@@ -93,9 +93,9 @@ ServerActiveObject* ObjectRef::getobject(ObjectRef *ref)
 LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
 {
 	ServerActiveObject *obj = getobject(ref);
-	if(obj == NULL)
+	if (obj == NULL)
 		return NULL;
-	if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
+	if (obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
 		return NULL;
 	return (LuaEntitySAO*)obj;
 }
@@ -103,9 +103,9 @@ LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
 PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
 {
 	ServerActiveObject *obj = getobject(ref);
-	if(obj == NULL)
+	if (obj == NULL)
 		return NULL;
-	if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
+	if (obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
 		return NULL;
 	return (PlayerSAO*)obj;
 }
@@ -113,7 +113,7 @@ PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
 Player* ObjectRef::getplayer(ObjectRef *ref)
 {
 	PlayerSAO *playersao = getplayersao(ref);
-	if(playersao == NULL)
+	if (playersao == NULL)
 		return NULL;
 	return playersao->getPlayer();
 }
@@ -160,7 +160,7 @@ int ObjectRef::l_getpos(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	v3f pos = co->getBasePosition() / BS;
 	lua_newtable(L);
 	lua_pushnumber(L, pos.X);
@@ -179,7 +179,7 @@ int ObjectRef::l_setpos(lua_State *L)
 	ObjectRef *ref = checkobject(L, 1);
 	//LuaEntitySAO *co = getluaobject(ref);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// pos
 	v3f pos = checkFloatPos(L, 2);
 	// Do it
@@ -194,7 +194,7 @@ int ObjectRef::l_moveto(lua_State *L)
 	ObjectRef *ref = checkobject(L, 1);
 	//LuaEntitySAO *co = getluaobject(ref);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// pos
 	v3f pos = checkFloatPos(L, 2);
 	// continuous
@@ -212,15 +212,15 @@ int ObjectRef::l_punch(lua_State *L)
 	ObjectRef *puncher_ref = checkobject(L, 2);
 	ServerActiveObject *co = getobject(ref);
 	ServerActiveObject *puncher = getobject(puncher_ref);
-	if(co == NULL) return 0;
-	if(puncher == NULL) return 0;
+	if (co == NULL) return 0;
+	if (puncher == NULL) return 0;
 	v3f dir;
-	if(lua_type(L, 5) != LUA_TTABLE)
+	if (lua_type(L, 5) != LUA_TTABLE)
 		dir = co->getBasePosition() - puncher->getBasePosition();
 	else
 		dir = read_v3f(L, 5);
 	float time_from_last_punch = 1000000;
-	if(lua_isnumber(L, 3))
+	if (lua_isnumber(L, 3))
 		time_from_last_punch = lua_tonumber(L, 3);
 	ToolCapabilities toolcap = read_tool_capabilities(L, 4);
 	dir.normalize();
@@ -253,8 +253,8 @@ int ObjectRef::l_right_click(lua_State *L)
 	ObjectRef *ref2 = checkobject(L, 2);
 	ServerActiveObject *co = getobject(ref);
 	ServerActiveObject *co2 = getobject(ref2);
-	if(co == NULL) return 0;
-	if(co2 == NULL) return 0;
+	if (co == NULL) return 0;
+	if (co2 == NULL) return 0;
 	// Do it
 	co->rightClick(co2);
 	return 0;
@@ -269,7 +269,7 @@ int ObjectRef::l_set_hp(lua_State *L)
 	ObjectRef *ref = checkobject(L, 1);
 	luaL_checknumber(L, 2);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	int hp = lua_tonumber(L, 2);
 	/*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
 			<<" hp="<<hp<<std::endl;*/
@@ -290,7 +290,7 @@ int ObjectRef::l_get_hp(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL){
+	if (co == NULL) {
 		// Default hp is 1
 		lua_pushnumber(L, 1);
 		return 1;
@@ -309,10 +309,10 @@ int ObjectRef::l_get_inventory(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	InventoryLocation loc = co->getInventoryLocation();
-	if(getServer(L)->getInventory(loc) != NULL)
+	if (getServer(L)->getInventory(loc) != NULL)
 		InvRef::create(L, loc);
 	else
 		lua_pushnil(L); // An object may have no inventory (nil)
@@ -325,7 +325,7 @@ int ObjectRef::l_get_wield_list(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	lua_pushstring(L, co->getWieldList().c_str());
 	return 1;
@@ -337,7 +337,7 @@ int ObjectRef::l_get_wield_index(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	lua_pushinteger(L, co->getWieldIndex() + 1);
 	return 1;
@@ -349,7 +349,7 @@ int ObjectRef::l_get_wielded_item(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL){
+	if (co == NULL) {
 		// Empty ItemStack
 		LuaItemStack::create(L, ItemStack());
 		return 1;
@@ -365,7 +365,7 @@ int ObjectRef::l_set_wielded_item(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	ItemStack item = read_item(L, 2, getServer(L));
 	bool success = co->setWieldedItem(item);
@@ -382,7 +382,7 @@ int ObjectRef::l_set_armor_groups(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	ItemGroupList groups;
 	read_groups(L, 2, groups);
@@ -410,7 +410,7 @@ int ObjectRef::l_set_physics_override(lua_State *L)
 {
 	ObjectRef *ref = checkobject(L, 1);
 	PlayerSAO *co = (PlayerSAO *) getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	if (lua_istable(L, 2)) {
 		co->m_physics_override_speed = getfloatfield_default(L, 2, "speed", co->m_physics_override_speed);
@@ -421,15 +421,15 @@ int ObjectRef::l_set_physics_override(lua_State *L)
 		co->m_physics_override_sent = false;
 	} else {
 		// old, non-table format
-		if(!lua_isnil(L, 2)){
+		if (!lua_isnil(L, 2)) {
 			co->m_physics_override_speed = lua_tonumber(L, 2);
 			co->m_physics_override_sent = false;
 		}
-		if(!lua_isnil(L, 3)){
+		if (!lua_isnil(L, 3)) {
 			co->m_physics_override_jump = lua_tonumber(L, 3);
 			co->m_physics_override_sent = false;
 		}
-		if(!lua_isnil(L, 4)){
+		if (!lua_isnil(L, 4)) {
 			co->m_physics_override_gravity = lua_tonumber(L, 4);
 			co->m_physics_override_sent = false;
 		}
@@ -465,19 +465,19 @@ int ObjectRef::l_set_animation(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	v2f frames = v2f(1, 1);
-	if(!lua_isnil(L, 2))
+	if (!lua_isnil(L, 2))
 		frames = read_v2f(L, 2);
 	float frame_speed = 15;
-	if(!lua_isnil(L, 3))
+	if (!lua_isnil(L, 3))
 		frame_speed = lua_tonumber(L, 3);
 	float frame_blend = 0;
-	if(!lua_isnil(L, 4))
+	if (!lua_isnil(L, 4))
 		frame_blend = lua_tonumber(L, 4);
 	bool frame_loop = true;
-	if(lua_isboolean(L, 5))
+	if (lua_isboolean(L, 5))
 		frame_loop = lua_toboolean(L, 5);
 	co->setAnimation(frames, frame_speed, frame_blend, frame_loop);
 	return 0;
@@ -516,11 +516,11 @@ int ObjectRef::l_set_local_animation(lua_State *L)
 	// Do it
 	v2s32 frames[4];
 	for (int i=0;i<4;i++) {
-		if(!lua_isnil(L, 2+1))
+		if (!lua_isnil(L, 2+1))
 			frames[i] = read_v2s32(L, 2+i);
 	}
 	float frame_speed = 30;
-	if(!lua_isnil(L, 6))
+	if (!lua_isnil(L, 6))
 		frame_speed = lua_tonumber(L, 6);
 
 	if (!getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed))
@@ -563,9 +563,9 @@ int ObjectRef::l_set_eye_offset(lua_State *L)
 	v3f offset_first = v3f(0, 0, 0);
 	v3f offset_third = v3f(0, 0, 0);
 
-	if(!lua_isnil(L, 2))
+	if (!lua_isnil(L, 2))
 		offset_first = read_v3f(L, 2);
-	if(!lua_isnil(L, 3))
+	if (!lua_isnil(L, 3))
 		offset_third = read_v3f(L, 3);
 
 	// Prevent abuse of offset values (keep player always visible)
@@ -601,16 +601,16 @@ int ObjectRef::l_set_bone_position(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	std::string bone = "";
-	if(!lua_isnil(L, 2))
+	if (!lua_isnil(L, 2))
 		bone = lua_tostring(L, 2);
 	v3f position = v3f(0, 0, 0);
-	if(!lua_isnil(L, 3))
+	if (!lua_isnil(L, 3))
 		position = read_v3f(L, 3);
 	v3f rotation = v3f(0, 0, 0);
-	if(!lua_isnil(L, 4))
+	if (!lua_isnil(L, 4))
 		rotation = read_v3f(L, 4);
 	co->setBonePosition(bone, position, rotation);
 	return 0;
@@ -626,7 +626,7 @@ int ObjectRef::l_get_bone_position(lua_State *L)
 		return 0;
 	// Do it
 	std::string bone = "";
-	if(!lua_isnil(L, 2))
+	if (!lua_isnil(L, 2))
 		bone = lua_tostring(L, 2);
 
 	v3f position = v3f(0, 0, 0);
@@ -738,9 +738,9 @@ int ObjectRef::l_set_properties(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	ServerActiveObject *co = getobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	ObjectProperties *prop = co->accessObjectProperties();
-	if(!prop)
+	if (!prop)
 		return 0;
 	read_object_properties(L, 2, prop);
 	co->notifyObjectPropertiesModified();
@@ -780,7 +780,7 @@ int ObjectRef::l_setvelocity(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	v3f pos = checkFloatPos(L, 2);
 	// Do it
 	co->setVelocity(pos);
@@ -793,7 +793,7 @@ int ObjectRef::l_getvelocity(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	v3f v = co->getVelocity();
 	pushFloatPos(L, v);
@@ -806,7 +806,7 @@ int ObjectRef::l_setacceleration(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// pos
 	v3f pos = checkFloatPos(L, 2);
 	// Do it
@@ -820,7 +820,7 @@ int ObjectRef::l_getacceleration(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	v3f v = co->getAcceleration();
 	pushFloatPos(L, v);
@@ -833,7 +833,7 @@ int ObjectRef::l_setyaw(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
 	// Do it
 	co->setYaw(yaw);
@@ -846,7 +846,7 @@ int ObjectRef::l_getyaw(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	float yaw = co->getYaw() * core::DEGTORAD;
 	lua_pushnumber(L, yaw);
@@ -859,7 +859,7 @@ int ObjectRef::l_settexturemod(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	std::string mod = luaL_checkstring(L, 2);
 	co->setTextureMod(mod);
@@ -873,19 +873,19 @@ int ObjectRef::l_setsprite(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	v2s16 p(0,0);
-	if(!lua_isnil(L, 2))
+	if (!lua_isnil(L, 2))
 		p = read_v2s16(L, 2);
 	int num_frames = 1;
-	if(!lua_isnil(L, 3))
+	if (!lua_isnil(L, 3))
 		num_frames = lua_tonumber(L, 3);
 	float framelength = 0.2;
-	if(!lua_isnil(L, 4))
+	if (!lua_isnil(L, 4))
 		framelength = lua_tonumber(L, 4);
 	bool select_horiz_by_yawpitch = false;
-	if(!lua_isnil(L, 5))
+	if (!lua_isnil(L, 5))
 		select_horiz_by_yawpitch = lua_toboolean(L, 5);
 	co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
 	return 0;
@@ -899,7 +899,7 @@ int ObjectRef::l_get_entity_name(lua_State *L)
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
 	log_deprecated(L,"Deprecated call to \"get_entity_name");
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	std::string name = co->getName();
 	lua_pushstring(L, name.c_str());
@@ -912,7 +912,7 @@ int ObjectRef::l_get_luaentity(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	LuaEntitySAO *co = getluaobject(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	luaentity_get(L, co->getId());
 	return 1;
@@ -936,7 +936,7 @@ int ObjectRef::l_get_player_name(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL){
+	if (player == NULL) {
 		lua_pushlstring(L, "", 0);
 		return 1;
 	}
@@ -945,13 +945,28 @@ int ObjectRef::l_get_player_name(lua_State *L)
 	return 1;
 }
 
+// get_player_velocity(self)
+int ObjectRef::l_get_player_velocity(lua_State *L)
+{
+	NO_MAP_LOCK_REQUIRED;
+	ObjectRef *ref = checkobject(L, 1);
+	Player *player = getplayer(ref);
+	if (player == NULL) {
+		lua_pushnil(L);
+		return 1;
+	}
+	// Do it
+	push_v3f(L, player->getSpeed() / BS);
+	return 1;
+}
+
 // get_look_dir(self)
 int ObjectRef::l_get_look_dir(lua_State *L)
 {
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL) return 0;
+	if (player == NULL) return 0;
 	// Do it
 	float pitch = player->getRadPitch();
 	float yaw = player->getRadYaw();
@@ -966,7 +981,7 @@ int ObjectRef::l_get_look_pitch(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL) return 0;
+	if (player == NULL) return 0;
 	// Do it
 	lua_pushnumber(L, player->getRadPitch());
 	return 1;
@@ -978,7 +993,7 @@ int ObjectRef::l_get_look_yaw(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL) return 0;
+	if (player == NULL) return 0;
 	// Do it
 	lua_pushnumber(L, player->getRadYaw());
 	return 1;
@@ -990,7 +1005,7 @@ int ObjectRef::l_set_look_pitch(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	PlayerSAO* co = getplayersao(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
 	// Do it
 	co->setPitch(pitch);
@@ -1003,7 +1018,7 @@ int ObjectRef::l_set_look_yaw(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	PlayerSAO* co = getplayersao(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
 	// Do it
 	co->setYaw(yaw);
@@ -1016,7 +1031,7 @@ int ObjectRef::l_set_breath(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	PlayerSAO* co = getplayersao(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	u16 breath = luaL_checknumber(L, 2);
 	// Do it
 	co->setBreath(breath);
@@ -1034,7 +1049,7 @@ int ObjectRef::l_get_breath(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	PlayerSAO* co = getplayersao(ref);
-	if(co == NULL) return 0;
+	if (co == NULL) return 0;
 	// Do it
 	u16 breath = co->getBreath();
 	lua_pushinteger (L, breath);
@@ -1047,7 +1062,7 @@ int ObjectRef::l_set_inventory_formspec(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL) return 0;
+	if (player == NULL) return 0;
 	std::string formspec = luaL_checkstring(L, 2);
 
 	player->inventory_formspec = formspec;
@@ -1062,7 +1077,7 @@ int ObjectRef::l_get_inventory_formspec(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL) return 0;
+	if (player == NULL) return 0;
 
 	std::string formspec = player->inventory_formspec;
 	lua_pushlstring(L, formspec.c_str(), formspec.size());
@@ -1075,7 +1090,7 @@ int ObjectRef::l_get_player_control(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL){
+	if (player == NULL) {
 		lua_pushlstring(L, "", 0);
 		return 1;
 	}
@@ -1109,7 +1124,7 @@ int ObjectRef::l_get_player_control_bits(lua_State *L)
 	NO_MAP_LOCK_REQUIRED;
 	ObjectRef *ref = checkobject(L, 1);
 	Player *player = getplayer(ref);
-	if(player == NULL){
+	if (player == NULL) {
 		lua_pushlstring(L, "", 0);
 		return 1;
 	}
@@ -1533,7 +1548,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
 
 	bool do_override = false;
 	float ratio = 0.0f;
-	if (!lua_isnil(L, 2)){
+	if (!lua_isnil(L, 2)) {
 		do_override = true;
 		ratio = luaL_checknumber(L, 2);
 	}
@@ -1612,7 +1627,7 @@ ObjectRef::ObjectRef(ServerActiveObject *object):
 
 ObjectRef::~ObjectRef()
 {
-	/*if(m_object)
+	/*if (m_object)
 		infostream<<"ObjectRef destructing for id="
 				<<m_object->getId()<<std::endl;
 	else
@@ -1706,6 +1721,7 @@ const luaL_reg ObjectRef::methods[] = {
 	luamethod(ObjectRef, is_player),
 	luamethod(ObjectRef, is_player_connected),
 	luamethod(ObjectRef, get_player_name),
+	luamethod(ObjectRef, get_player_velocity),
 	luamethod(ObjectRef, get_look_dir),
 	luamethod(ObjectRef, get_look_pitch),
 	luamethod(ObjectRef, get_look_yaw),
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index 9e4a62058..a4457cc05 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -183,6 +183,9 @@ class ObjectRef : public ModApiBase {
 	// get_player_name(self)
 	static int l_get_player_name(lua_State *L);
 
+	// get_player_velocity(self)
+	static int l_get_player_velocity(lua_State *L);
+
 	// get_look_dir(self)
 	static int l_get_look_dir(lua_State *L);
 
-- 
GitLab