From d0753dddb112f717f5b636d194b2d7c3917ff0a8 Mon Sep 17 00:00:00 2001 From: sfence Date: Mon, 1 Jan 2024 22:48:56 +0100 Subject: [PATCH] Method add_pos for object/player (#14126) --- doc/lua_api.md | 13 +++++++++---- games/devtest/mods/unittests/player.lua | 16 +++++++++++++++ src/client/client.h | 1 + src/client/localplayer.h | 5 +++++ src/network/clientopcodes.cpp | 4 ++-- src/network/clientpackethandler.cpp | 11 +++++++++++ src/network/networkprotocol.h | 6 ++++++ src/script/lua_api/l_object.cpp | 16 +++++++++++++++ src/script/lua_api/l_object.h | 3 +++ src/server.cpp | 7 +++++++ src/server.h | 1 + src/server/player_sao.cpp | 26 ++++++++++++++++++++++++- src/server/player_sao.h | 1 + src/server/serveractiveobject.h | 2 ++ 14 files changed, 105 insertions(+), 7 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 7461127c2..b15040f99 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -7465,15 +7465,20 @@ child will follow movement and rotation of that bone. * Sets the position of the object. * No-op if object is attached. * `pos` is a vector `{x=num, y=num, z=num}` +* `add_pos(pos)`: + * Changes position by adding to the current position. + * No-op if object is attached. + * `pos` is a vector `{x=num, y=num, z=num}`. + * In comparison to using `set_pos`, `add_pos` will avoid synchronization problems. * `get_velocity()`: returns the velocity, a vector. * `add_velocity(vel)` * Changes velocity by adding to the current velocity. * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` - * In comparison to using get_velocity, adding the velocity and then using - set_velocity, add_velocity is supposed to avoid synchronization problems. - Additionally, players also do not support set_velocity. + * In comparison to using `get_velocity`, adding the velocity and then using + `set_velocity`, `add_velocity` is supposed to avoid synchronization problems. + Additionally, players also do not support `set_velocity`. * If object is a player: - * Does not apply during free_move. + * 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. diff --git a/games/devtest/mods/unittests/player.lua b/games/devtest/mods/unittests/player.lua index fa0557960..70b3b6cae 100644 --- a/games/devtest/mods/unittests/player.lua +++ b/games/devtest/mods/unittests/player.lua @@ -68,3 +68,19 @@ local function run_player_meta_tests(player) assert(meta:equals(meta2)) end unittests.register("test_player_meta", run_player_meta_tests, {player=true}) + +-- +-- Player add pos +-- +local function run_player_add_pos_tests(player) + local pos = player:get_pos() + player:add_pos(vector.new(0, 1000, 0)) + local newpos = player:get_pos() + player:add_pos(vector.new(0, -1000, 0)) + local backpos = player:get_pos() + local newdist = vector.distance(pos, newpos) + assert(math.abs(newdist - 1000) <= 1) + assert(vector.distance(pos, backpos) <= 1) +end +unittests.register("test_player_add_pos", run_player_add_pos_tests, {player=true}) + diff --git a/src/client/client.h b/src/client/client.h index 4c49301ce..b40c60828 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -196,6 +196,7 @@ public: void handleCommand_HP(NetworkPacket* pkt); void handleCommand_Breath(NetworkPacket* pkt); void handleCommand_MovePlayer(NetworkPacket* pkt); + void handleCommand_MovePlayerRel(NetworkPacket* pkt); void handleCommand_DeathScreen(NetworkPacket* pkt); void handleCommand_AnnounceMedia(NetworkPacket* pkt); void handleCommand_Media(NetworkPacket* pkt); diff --git a/src/client/localplayer.h b/src/client/localplayer.h index f33aab4b3..1133a3f56 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -129,6 +129,11 @@ public: m_position = position; m_sneak_node_exists = false; } + inline void addPosition(const v3f &added_pos) + { + m_position += added_pos; + m_sneak_node_exists = false; + } v3f getPosition() const { return m_position; } diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index bff318155..c3dbe57a9 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -117,13 +117,13 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_SET_SUN", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudSetSun }, // 0x5a { "TOCLIENT_SET_MOON", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudSetMoon }, // 0x5b { "TOCLIENT_SET_STARS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudSetStars }, // 0x5c - null_command_handler, + { "TOCLIENT_MOVE_PLAYER_REL", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MovePlayerRel }, // 0x5d, null_command_handler, null_command_handler, { "TOCLIENT_SRP_BYTES_S_B", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_SrpBytesSandB }, // 0x60 { "TOCLIENT_FORMSPEC_PREPEND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FormspecPrepend }, // 0x61, { "TOCLIENT_MINIMAP_MODES", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MinimapModes }, // 0x62, - { "TOCLIENT_SET_LIGHTING", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_SetLighting }, // 0x63, + { "TOCLIENT_SET_LIGHTING", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_SetLighting }, // 0x63, }; const static ServerCommandFactory null_command_factory = { "TOSERVER_NULL", 0, false }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 3c6da09a7..bacd7f8f0 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -635,6 +635,17 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt) m_client_event_queue.push(event); } +void Client::handleCommand_MovePlayerRel(NetworkPacket *pkt) +{ + v3f added_pos; + + *pkt >> added_pos; + + LocalPlayer *player = m_env.getLocalPlayer(); + assert(player); + player->addPosition(added_pos); +} + void Client::handleCommand_DeathScreen(NetworkPacket* pkt) { bool set_camera_point_target; diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 0ededba38..44d5e80fc 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -221,6 +221,7 @@ with this program; if not, write to the Free Software Foundation, Inc., [scheduled bump for 5.8.0] PROTOCOL VERSION 44: AO_CMD_SET_BONE_POSITION extended + Add TOCLIENT_MOVE_PLAYER_REL [scheduled bump for 5.9.0] */ @@ -835,6 +836,11 @@ enum ToClientCommand f32 day_opacity */ + TOCLIENT_MOVE_PLAYER_REL = 0x5d, + /* + v3f added_pos + */ + TOCLIENT_SRP_BYTES_S_B = 0x60, /* Belonging to AUTH_MECHANISM_SRP. diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index c9dae1885..11ad7a7fe 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -134,6 +134,21 @@ int ObjectRef::l_set_pos(lua_State *L) return 0; } +// add_pos(self, pos) +int ObjectRef::l_add_pos(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkObject(L, 1); + ServerActiveObject *sao = getobject(ref); + if (sao == nullptr) + return 0; + + v3f pos = checkFloatPos(L, 2); + + sao->addPos(pos); + return 0; +} + // move_to(self, pos, continuous) int ObjectRef::l_move_to(lua_State *L) { @@ -2597,6 +2612,7 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, remove), luamethod_aliased(ObjectRef, get_pos, getpos), luamethod_aliased(ObjectRef, set_pos, setpos), + luamethod(ObjectRef, add_pos), luamethod_aliased(ObjectRef, move_to, moveto), luamethod(ObjectRef, punch), luamethod(ObjectRef, right_click), diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 4465a823f..d8cc8d604 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -73,6 +73,9 @@ private: // set_pos(self, pos) static int l_set_pos(lua_State *L); + // add_pos(self, pos) + static int l_add_pos(lua_State *L); + // move_to(self, pos, continuous) static int l_move_to(lua_State *L); diff --git a/src/server.cpp b/src/server.cpp index 8c084a573..da9c5c10d 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1961,6 +1961,13 @@ void Server::SendMovePlayer(session_t peer_id) Send(&pkt); } +void Server::SendMovePlayerRel(session_t peer_id, const v3f &added_pos) +{ + NetworkPacket pkt(TOCLIENT_MOVE_PLAYER_REL, 0, peer_id); + pkt << added_pos; + Send(&pkt); +} + void Server::SendPlayerFov(session_t peer_id) { NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id); diff --git a/src/server.h b/src/server.h index 802612934..bec2fe1cf 100644 --- a/src/server.h +++ b/src/server.h @@ -364,6 +364,7 @@ public: void SendPlayerBreath(PlayerSAO *sao); void SendInventory(PlayerSAO *playerSAO, bool incremental); void SendMovePlayer(session_t peer_id); + void SendMovePlayerRel(session_t peer_id, const v3f &added_pos); void SendPlayerSpeed(session_t peer_id, const v3f &added_vel); void SendPlayerFov(session_t peer_id); diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index 681841f23..ede3ccb8e 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -352,7 +352,7 @@ void PlayerSAO::setBasePosition(v3f position) void PlayerSAO::setPos(const v3f &pos) { - if(isAttached()) + if (isAttached()) return; // Send mapblock of target location @@ -367,6 +367,30 @@ void PlayerSAO::setPos(const v3f &pos) m_env->getGameDef()->SendMovePlayer(m_peer_id); } +void PlayerSAO::addPos(const v3f &added_pos) +{ + if (isAttached()) + return; + + // Backward compatibility for older clients + if (m_player->protocol_version < 44) { + setPos(getBasePosition() + added_pos); + return; + } + + // Send mapblock of target location + v3f pos = getBasePosition() + added_pos; + v3s16 blockpos = v3s16(pos.X / MAP_BLOCKSIZE, pos.Y / MAP_BLOCKSIZE, pos.Z / MAP_BLOCKSIZE); + m_env->getGameDef()->SendBlock(m_peer_id, blockpos); + + setBasePosition(pos); + // Movement caused by this command is always valid + m_last_good_position = getBasePosition(); + m_move_pool.empty(); + m_time_from_last_teleport = 0.0; + m_env->getGameDef()->SendMovePlayerRel(m_peer_id, added_pos); +} + void PlayerSAO::moveTo(v3f pos, bool continuous) { if(isAttached()) diff --git a/src/server/player_sao.h b/src/server/player_sao.h index c0d395f80..854464508 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -90,6 +90,7 @@ public: void step(float dtime, bool send_recommended) override; void setBasePosition(v3f position); void setPos(const v3f &pos) override; + void addPos(const v3f &added_pos) override; void moveTo(v3f pos, bool continuous) override; void setPlayerYaw(const float yaw); // Data should not be sent at player initialization diff --git a/src/server/serveractiveobject.h b/src/server/serveractiveobject.h index a42096f7b..2911a5549 100644 --- a/src/server/serveractiveobject.h +++ b/src/server/serveractiveobject.h @@ -91,6 +91,8 @@ public: virtual void setPos(const v3f &pos) { setBasePosition(pos); } + virtual void addPos(const v3f &added_pos) + { setBasePosition(m_base_position + added_pos); } // continuous: if true, object does not stop immediately at pos virtual void moveTo(v3f pos, bool continuous) { setBasePosition(pos); }