Implement adding velocity to player from Lua

The intended usecase is knockback, but there's potential for more.
This commit is contained in:
sfan5 2019-07-16 14:00:42 +02:00
parent b19400aa74
commit cf64054390
14 changed files with 105 additions and 2 deletions

@ -5465,6 +5465,14 @@ This is basically a reference to a C++ `ServerActiveObject`
* `get_player_name()`: returns `""` if is not a player * `get_player_name()`: returns `""` if is not a player
* `get_player_velocity()`: returns `nil` if is not a player, otherwise a * `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 table {x, y, z} representing the player's instantaneous velocity in nodes/s
* `add_player_velocity(vel)`
* Adds to player velocity, this happens client-side and only once.
* Does not apply during free_move.
* Note that since the player speed is normalized at each move step,
increasing e.g. Y velocity beyond what would usually be achieved
(see: physics overrides) will cause existing X/Z velocity to be reduced.
* Example: `add_player_velocity({x=0, y=6.5, z=0})` is equivalent to
pressing the jump key (assuming default settings)
* `get_look_dir()`: get camera direction as a unit vector * `get_look_dir()`: get camera direction as a unit vector
* `get_look_vertical()`: pitch in radians * `get_look_vertical()`: pitch in radians
* Angle ranges between -pi/2 and pi/2, which are straight up and down * Angle ranges between -pi/2 and pi/2, which are straight up and down

@ -227,6 +227,7 @@ public:
void handleCommand_SrpBytesSandB(NetworkPacket *pkt); void handleCommand_SrpBytesSandB(NetworkPacket *pkt);
void handleCommand_FormspecPrepend(NetworkPacket *pkt); void handleCommand_FormspecPrepend(NetworkPacket *pkt);
void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt); void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt);
void handleCommand_PlayerSpeed(NetworkPacket *pkt);
void ProcessData(NetworkPacket *pkt); void ProcessData(NetworkPacket *pkt);

@ -188,6 +188,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
// Copy parent position if local player is attached // Copy parent position if local player is attached
if (isAttached) { if (isAttached) {
setPosition(overridePosition); setPosition(overridePosition);
added_velocity = v3f(); // ignored
return; return;
} }
@ -201,9 +202,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if (noclip && free_move) { if (noclip && free_move) {
position += m_speed * dtime; position += m_speed * dtime;
setPosition(position); setPosition(position);
added_velocity = v3f(); // ignored
return; return;
} }
m_speed += added_velocity;
added_velocity = v3f();
/* /*
Collision detection Collision detection
*/ */
@ -782,6 +787,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
if (isAttached) { if (isAttached) {
setPosition(overridePosition); setPosition(overridePosition);
m_sneak_node_exists = false; m_sneak_node_exists = false;
added_velocity = v3f();
return; return;
} }
@ -795,9 +801,13 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
position += m_speed * dtime; position += m_speed * dtime;
setPosition(position); setPosition(position);
m_sneak_node_exists = false; m_sneak_node_exists = false;
added_velocity = v3f();
return; return;
} }
m_speed += added_velocity;
added_velocity = v3f();
/* /*
Collision detection Collision detection
*/ */

@ -149,6 +149,11 @@ public:
bool getAutojump() const { return m_autojump; } bool getAutojump() const { return m_autojump; }
inline void addVelocity(const v3f &vel)
{
added_velocity += vel;
}
private: private:
void accelerate(const v3f &target_speed, const f32 max_increase_H, void accelerate(const v3f &target_speed, const f32 max_increase_H,
const f32 max_increase_V, const bool use_pitch); const f32 max_increase_V, const bool use_pitch);
@ -194,6 +199,7 @@ private:
float m_zoom_fov = 0.0f; float m_zoom_fov = 0.0f;
bool m_autojump = false; bool m_autojump = false;
float m_autojump_time = 0.0f; float m_autojump_time = 0.0f;
v3f added_velocity = v3f(0.0f, 0.0f, 0.0f); // cleared on each move()
GenericCAO *m_cao = nullptr; GenericCAO *m_cao = nullptr;
Client *m_client; Client *m_client;

@ -1091,6 +1091,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_time_from_last_teleport += dtime; m_time_from_last_teleport += dtime;
m_time_from_last_punch += dtime; m_time_from_last_punch += dtime;
m_nocheat_dig_time += dtime; m_nocheat_dig_time += dtime;
m_max_speed_override_time = MYMAX(m_max_speed_override_time - dtime, 0.0f);
// Each frame, parent position is copied if the object is attached, // Each frame, parent position is copied if the object is attached,
// otherwise it's calculated normally. // otherwise it's calculated normally.
@ -1412,6 +1413,19 @@ std::string PlayerSAO::getPropertyPacket()
return gob_cmd_set_properties(m_prop); return gob_cmd_set_properties(m_prop);
} }
void PlayerSAO::setMaxSpeedOverride(const v3f &vel)
{
if (m_max_speed_override_time == 0.0f)
m_max_speed_override = vel;
else
m_max_speed_override += vel;
if (m_player) {
float accel = MYMIN(m_player->movement_acceleration_default,
m_player->movement_acceleration_air);
m_max_speed_override_time = m_max_speed_override.getLength() / accel / BS;
}
}
bool PlayerSAO::checkMovementCheat() bool PlayerSAO::checkMovementCheat()
{ {
if (isAttached() || m_is_singleplayer || if (isAttached() || m_is_singleplayer ||
@ -1431,6 +1445,14 @@ bool PlayerSAO::checkMovementCheat()
too, and much more lightweight. too, and much more lightweight.
*/ */
float override_max_H, override_max_V;
if (m_max_speed_override_time > 0.0f) {
override_max_H = MYMAX(fabs(m_max_speed_override.X), fabs(m_max_speed_override.Z));
override_max_V = fabs(m_max_speed_override.Y);
} else {
override_max_H = override_max_V = 0.0f;
}
float player_max_walk = 0; // horizontal movement float player_max_walk = 0; // horizontal movement
float player_max_jump = 0; // vertical upwards movement float player_max_jump = 0; // vertical upwards movement
@ -1439,10 +1461,13 @@ bool PlayerSAO::checkMovementCheat()
else else
player_max_walk = m_player->movement_speed_walk; // Normal speed player_max_walk = m_player->movement_speed_walk; // Normal speed
player_max_walk *= m_physics_override_speed; player_max_walk *= m_physics_override_speed;
player_max_walk = MYMAX(player_max_walk, override_max_H);
player_max_jump = m_player->movement_speed_jump * m_physics_override_jump; player_max_jump = m_player->movement_speed_jump * m_physics_override_jump;
// FIXME: Bouncy nodes cause practically unbound increase in Y speed, // FIXME: Bouncy nodes cause practically unbound increase in Y speed,
// until this can be verified correctly, tolerate higher jumping speeds // until this can be verified correctly, tolerate higher jumping speeds
player_max_jump *= 2.0; player_max_jump *= 2.0;
player_max_jump = MYMAX(player_max_jump, override_max_V);
// Don't divide by zero! // Don't divide by zero!
if (player_max_walk < 0.0001f) if (player_max_walk < 0.0001f)

@ -322,6 +322,7 @@ public:
{ {
return m_dig_pool; return m_dig_pool;
} }
void setMaxSpeedOverride(const v3f &vel);
// Returns true if cheated // Returns true if cheated
bool checkMovementCheat(); bool checkMovementCheat();
@ -361,6 +362,8 @@ private:
float m_time_from_last_punch = 0.0f; float m_time_from_last_punch = 0.0f;
v3s16 m_nocheat_dig_pos = v3s16(32767, 32767, 32767); v3s16 m_nocheat_dig_pos = v3s16(32767, 32767, 32767);
float m_nocheat_dig_time = 0.0f; float m_nocheat_dig_time = 0.0f;
float m_max_speed_override_time = 0.0f;
v3f m_max_speed_override = v3f(0.0f, 0.0f, 0.0f);
// Timers // Timers
IntervalLimiter m_breathing_interval; IntervalLimiter m_breathing_interval;

@ -67,7 +67,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
null_command_handler, null_command_handler,
{ "TOCLIENT_TIME_OF_DAY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_TimeOfDay }, // 0x29 { "TOCLIENT_TIME_OF_DAY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_TimeOfDay }, // 0x29
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CSMRestrictionFlags }, // 0x2A { "TOCLIENT_CSM_RESTRICTION_FLAGS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CSMRestrictionFlags }, // 0x2A
null_command_handler, { "TOCLIENT_PLAYER_SPEED", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_PlayerSpeed }, // 0x2B
null_command_handler, null_command_handler,
null_command_handler, null_command_handler,
null_command_handler, null_command_handler,

@ -1383,6 +1383,17 @@ void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
loadMods(); loadMods();
} }
void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
{
v3f added_vel;
*pkt >> added_vel;
LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);
player->addVelocity(added_vel);
}
/* /*
* Mod channels * Mod channels
*/ */

@ -194,6 +194,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
New network float format New network float format
ContentFeatures version 13 ContentFeatures version 13
Add full Euler rotations instead of just yaw Add full Euler rotations instead of just yaw
Add TOCLIENT_PLAYER_SPEED
*/ */
#define LATEST_PROTOCOL_VERSION 37 #define LATEST_PROTOCOL_VERSION 37
@ -295,6 +296,11 @@ enum ToClientCommand
u32 CSMRestrictionFlags byteflag u32 CSMRestrictionFlags byteflag
*/ */
TOCLIENT_PLAYER_SPEED = 0x2B,
/*
v3f added_vel
*/
// (oops, there is some gap here) // (oops, there is some gap here)
TOCLIENT_CHAT_MESSAGE = 0x2F, TOCLIENT_CHAT_MESSAGE = 0x2F,

@ -156,7 +156,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
null_command_factory, null_command_factory,
{ "TOCLIENT_TIME_OF_DAY", 0, true }, // 0x29 { "TOCLIENT_TIME_OF_DAY", 0, true }, // 0x29
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", 0, true }, // 0x2A { "TOCLIENT_CSM_RESTRICTION_FLAGS", 0, true }, // 0x2A
null_command_factory, { "TOCLIENT_PLAYER_SPEED", 0, true }, // 0x2B
null_command_factory, null_command_factory,
null_command_factory, null_command_factory,
null_command_factory, null_command_factory,

@ -1092,6 +1092,27 @@ int ObjectRef::l_get_player_velocity(lua_State *L)
return 1; return 1;
} }
// add_player_velocity(self, {x=num, y=num, z=num})
int ObjectRef::l_add_player_velocity(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
v3f vel = checkFloatPos(L, 2);
RemotePlayer *player = getplayer(ref);
PlayerSAO *co = getplayersao(ref);
if (!player || !co)
return 0;
session_t peer_id = player->getPeerId();
if (peer_id == PEER_ID_INEXISTENT)
return 0;
// Do it
co->setMaxSpeedOverride(vel);
getServer(L)->SendPlayerSpeed(peer_id, vel);
return 0;
}
// get_look_dir(self) // get_look_dir(self)
int ObjectRef::l_get_look_dir(lua_State *L) int ObjectRef::l_get_look_dir(lua_State *L)
{ {
@ -1931,6 +1952,7 @@ luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, is_player_connected), luamethod(ObjectRef, is_player_connected),
luamethod(ObjectRef, get_player_name), luamethod(ObjectRef, get_player_name),
luamethod(ObjectRef, get_player_velocity), luamethod(ObjectRef, get_player_velocity),
luamethod(ObjectRef, add_player_velocity),
luamethod(ObjectRef, get_look_dir), luamethod(ObjectRef, get_look_dir),
luamethod(ObjectRef, get_look_pitch), luamethod(ObjectRef, get_look_pitch),
luamethod(ObjectRef, get_look_yaw), luamethod(ObjectRef, get_look_yaw),

@ -212,6 +212,9 @@ private:
// get_player_velocity(self) // get_player_velocity(self)
static int l_get_player_velocity(lua_State *L); static int l_get_player_velocity(lua_State *L);
// add_player_velocity(self, {x=num, y=num, z=num})
static int l_add_player_velocity(lua_State *L);
// get_look_dir(self) // get_look_dir(self)
static int l_get_look_dir(lua_State *L); static int l_get_look_dir(lua_State *L);

@ -1958,6 +1958,13 @@ void Server::SendCSMRestrictionFlags(session_t peer_id)
Send(&pkt); Send(&pkt);
} }
void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
{
NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
pkt << added_vel;
Send(&pkt);
}
s32 Server::playSound(const SimpleSoundSpec &spec, s32 Server::playSound(const SimpleSoundSpec &spec,
const ServerSoundParams &params) const ServerSoundParams &params)
{ {

@ -335,6 +335,7 @@ public:
void SendPlayerBreath(PlayerSAO *sao); void SendPlayerBreath(PlayerSAO *sao);
void SendInventory(PlayerSAO* playerSAO); void SendInventory(PlayerSAO* playerSAO);
void SendMovePlayer(session_t peer_id); void SendMovePlayer(session_t peer_id);
void SendPlayerSpeed(session_t peer_id, const v3f &added_vel);
virtual bool registerModStorage(ModMetadata *storage); virtual bool registerModStorage(ModMetadata *storage);
virtual void unregisterModStorage(const std::string &name); virtual void unregisterModStorage(const std::string &name);