Implement adding velocity to player from Lua
authorsfan5 <sfan5@live.de>
Tue, 16 Jul 2019 12:00:42 +0000 (14:00 +0200)
committersfan5 <sfan5@live.de>
Sat, 10 Aug 2019 17:44:27 +0000 (19:44 +0200)
The intended usecase is knockback, but there's potential for more.

14 files changed:
doc/lua_api.txt
src/client/client.h
src/client/localplayer.cpp
src/client/localplayer.h
src/content_sao.cpp
src/content_sao.h
src/network/clientopcodes.cpp
src/network/clientpackethandler.cpp
src/network/networkprotocol.h
src/network/serveropcodes.cpp
src/script/lua_api/l_object.cpp
src/script/lua_api/l_object.h
src/server.cpp
src/server.h

index 840841e6b6eaded349acd6ac31f9dbbac244e1f1..9fd2ba3f597e0fe38408438f9a24d538aa961f9b 100644 (file)
@@ -5465,6 +5465,14 @@ This is basically a reference to a C++ `ServerActiveObject`
 * `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
+* `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_vertical()`: pitch in radians
     * Angle ranges between -pi/2 and pi/2, which are straight up and down
index 15a4689c19ae8b4eede99fa0ef8e0a751843b8e0..3bfb1631e1f117e4d24d8222f99e1e91e21938a1 100644 (file)
@@ -227,6 +227,7 @@ public:
        void handleCommand_SrpBytesSandB(NetworkPacket *pkt);
        void handleCommand_FormspecPrepend(NetworkPacket *pkt);
        void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt);
+       void handleCommand_PlayerSpeed(NetworkPacket *pkt);
 
        void ProcessData(NetworkPacket *pkt);
 
index 0e273a16a4c7fd39cb966e72244771d8960a00a6..c356f7c24a9c5c6d2fbcebdf553b88c1ad181b52 100644 (file)
@@ -188,6 +188,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
        // Copy parent position if local player is attached
        if (isAttached) {
                setPosition(overridePosition);
+               added_velocity = v3f(); // ignored
                return;
        }
 
@@ -201,9 +202,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
        if (noclip && free_move) {
                position += m_speed * dtime;
                setPosition(position);
+               added_velocity = v3f(); // ignored
                return;
        }
 
+       m_speed += added_velocity;
+       added_velocity = v3f();
+
        /*
                Collision detection
        */
@@ -782,6 +787,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
        if (isAttached) {
                setPosition(overridePosition);
                m_sneak_node_exists = false;
+               added_velocity = v3f();
                return;
        }
 
@@ -795,9 +801,13 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
                position += m_speed * dtime;
                setPosition(position);
                m_sneak_node_exists = false;
+               added_velocity = v3f();
                return;
        }
 
+       m_speed += added_velocity;
+       added_velocity = v3f();
+
        /*
                Collision detection
        */
index 84cfa583a31accecd3e65c071ce432641de3c030..16e7996ae8ebba9f92eb198bfbfe2490939ad428 100644 (file)
@@ -149,6 +149,11 @@ public:
 
        bool getAutojump() const { return m_autojump; }
 
+       inline void addVelocity(const v3f &vel)
+       {
+               added_velocity += vel;
+       }
+
 private:
        void accelerate(const v3f &target_speed, const f32 max_increase_H,
                        const f32 max_increase_V, const bool use_pitch);
@@ -194,6 +199,7 @@ private:
        float m_zoom_fov = 0.0f;
        bool m_autojump = false;
        float m_autojump_time = 0.0f;
+       v3f added_velocity = v3f(0.0f, 0.0f, 0.0f); // cleared on each move()
 
        GenericCAO *m_cao = nullptr;
        Client *m_client;
index 0f1e2f435c623f3d29362be128f48038d28765ab..de300481fd1e0a06b8a77e5710817d2d3e04aeff 100644 (file)
@@ -1091,6 +1091,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
        m_time_from_last_teleport += dtime;
        m_time_from_last_punch += 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,
        // otherwise it's calculated normally.
@@ -1412,6 +1413,19 @@ std::string PlayerSAO::getPropertyPacket()
        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()
 {
        if (isAttached() || m_is_singleplayer ||
@@ -1431,6 +1445,14 @@ bool PlayerSAO::checkMovementCheat()
                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_jump = 0; // vertical upwards movement
 
@@ -1439,10 +1461,13 @@ bool PlayerSAO::checkMovementCheat()
        else
                player_max_walk = m_player->movement_speed_walk; // Normal 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;
        // FIXME: Bouncy nodes cause practically unbound increase in Y speed,
        //        until this can be verified correctly, tolerate higher jumping speeds
        player_max_jump *= 2.0;
+       player_max_jump = MYMAX(player_max_jump, override_max_V);
 
        // Don't divide by zero!
        if (player_max_walk < 0.0001f)
index beaf697e632f075338ec5bda9b08701f532ba9b7..2dd839e119f2a888803732d7a7ed90c7a8fee2cf 100644 (file)
@@ -322,6 +322,7 @@ public:
        {
                return m_dig_pool;
        }
+       void setMaxSpeedOverride(const v3f &vel);
        // Returns true if cheated
        bool checkMovementCheat();
 
@@ -361,6 +362,8 @@ private:
        float m_time_from_last_punch = 0.0f;
        v3s16 m_nocheat_dig_pos = v3s16(32767, 32767, 32767);
        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
        IntervalLimiter m_breathing_interval;
index 7f3ab50ed749e0d0ab931b85bb61efe8f7fbd8ef..8641cadecbbc92c0b02820df23fe92ca9bb3752a 100644 (file)
@@ -67,7 +67,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
        null_command_handler,
        { "TOCLIENT_TIME_OF_DAY",              TOCLIENT_STATE_CONNECTED, &Client::handleCommand_TimeOfDay }, // 0x29
        { "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,
index 1ae47d190edadf00a6d15b636446405e63721ba4..520fcfa812a8e5a1ac0ee16bf49e6968a519d4b6 100644 (file)
@@ -1383,6 +1383,17 @@ void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
        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
  */
index 0ab11ee7e962ec060a2ee3365792f9084bb1fabb..451518bbf5deb45fcc8dd8672594daa66161c180 100644 (file)
@@ -194,6 +194,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
                New network float format
                ContentFeatures version 13
                Add full Euler rotations instead of just yaw
+               Add TOCLIENT_PLAYER_SPEED
 */
 
 #define LATEST_PROTOCOL_VERSION 37
@@ -295,6 +296,11 @@ enum ToClientCommand
                u32 CSMRestrictionFlags byteflag
         */
 
+       TOCLIENT_PLAYER_SPEED = 0x2B,
+       /*
+               v3f added_vel
+        */
+
        // (oops, there is some gap here)
 
        TOCLIENT_CHAT_MESSAGE = 0x2F,
index 013b549c61a5b859d77cb219d02c2126bd55729e..8c5579a369168cd543ca798ba2c06ce409b99d54 100644 (file)
@@ -156,7 +156,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
        null_command_factory,
        { "TOCLIENT_TIME_OF_DAY",              0, true }, // 0x29
        { "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,
index 5dba631591977cf9a5c70357f64b7658b8746033..be2172f1b853d5cd4a80e37bb5ef4cdce244d43c 100644 (file)
@@ -1092,6 +1092,27 @@ int ObjectRef::l_get_player_velocity(lua_State *L)
        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)
 int ObjectRef::l_get_look_dir(lua_State *L)
 {
@@ -1931,6 +1952,7 @@ luaL_Reg ObjectRef::methods[] = {
        luamethod(ObjectRef, is_player_connected),
        luamethod(ObjectRef, get_player_name),
        luamethod(ObjectRef, get_player_velocity),
+       luamethod(ObjectRef, add_player_velocity),
        luamethod(ObjectRef, get_look_dir),
        luamethod(ObjectRef, get_look_pitch),
        luamethod(ObjectRef, get_look_yaw),
index 653d833f674da68a289858b2e615c8b4bb76604d..2390c51958371eaceb9ae7e3074a73dc20dd40f2 100644 (file)
@@ -212,6 +212,9 @@ private:
        // get_player_velocity(self)
        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)
        static int l_get_look_dir(lua_State *L);
 
index 27388e66648850526ec2f587853e07986a139e70..5dd3d00612363e79be6d51055c3f7df4e425e2ea 100644 (file)
@@ -1958,6 +1958,13 @@ void Server::SendCSMRestrictionFlags(session_t peer_id)
        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,
                const ServerSoundParams &params)
 {
index 4232653ebcd9053aca3e59cb13d2df41b4e1f131..06adbad689beb40115b7a87ddf2b4ab5760d67c5 100644 (file)
@@ -335,6 +335,7 @@ public:
        void SendPlayerBreath(PlayerSAO *sao);
        void SendInventory(PlayerSAO* playerSAO);
        void SendMovePlayer(session_t peer_id);
+       void SendPlayerSpeed(session_t peer_id, const v3f &added_vel);
 
        virtual bool registerModStorage(ModMetadata *storage);
        virtual void unregisterModStorage(const std::string &name);