From 06907aa99b56ecd9c30e483a7cf3a77678293bfa Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Mon, 2 Sep 2024 21:11:08 +0200 Subject: [PATCH] Support floating-point animation frame numbers --- doc/lua_api.md | 3 +- games/devtest/mods/gltf/init.lua | 14 +++++++-- irr/include/IAnimatedMesh.h | 24 ++++------------ irr/include/IAnimatedMeshSceneNode.h | 8 +++--- irr/include/SAnimatedMesh.h | 21 +++++--------- irr/include/vector2d.h | 6 ++++ irr/src/CAnimatedMeshSceneNode.cpp | 43 ++++++++++++++-------------- irr/src/CAnimatedMeshSceneNode.h | 10 +++---- irr/src/CMeshManipulator.cpp | 2 +- irr/src/CSkinnedMesh.cpp | 12 ++++---- irr/src/CSkinnedMesh.h | 8 +++--- src/client/content_cao.cpp | 7 ++--- src/client/content_cao.h | 2 +- src/gui/guiScene.cpp | 2 +- src/gui/guiScene.h | 2 +- src/network/clientpackethandler.cpp | 15 ++++++---- src/network/networkprotocol.cpp | 1 + src/player.h | 2 +- src/remoteplayer.h | 4 +-- src/script/lua_api/l_object.cpp | 10 +++---- src/server.cpp | 16 ++++++++--- src/server.h | 4 +-- 22 files changed, 111 insertions(+), 105 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 0596c1e2f..a78afc847 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8059,8 +8059,7 @@ child will follow movement and rotation of that bone. * Animation interpolates towards the end frame but stops when it is reached * If looped, there is no interpolation back to the start frame * If looped, the model should look identical at start and end - * Only integer numbers are supported - * default: `{x=1, y=1}` + * default: `{x=1.0, y=1.0}` * `frame_speed`: How fast the animation plays, in frames per second (number) * default: `15.0` * `frame_blend`: number, default: `0.0` diff --git a/games/devtest/mods/gltf/init.lua b/games/devtest/mods/gltf/init.lua index 1a17ac05f..252fd017d 100644 --- a/games/devtest/mods/gltf/init.lua +++ b/games/devtest/mods/gltf/init.lua @@ -55,10 +55,20 @@ minetest.register_entity("gltf:simple_skin", { end }) --- Note: Model has an animation, but we can use it as a static test nevertheless -- The claws rendering incorrectly from one side is expected behavior: -- They use an unsupported double-sided material. -register_entity("frog", {"gltf_frog.png"}, false) +minetest.register_entity("gltf:frog", { + initial_properties = { + visual = "mesh", + mesh = "gltf_frog.gltf", + textures = {"gltf_frog.png"}, + backface_culling = false + }, + on_activate = function(self) + self.object:set_animation({x = 0, y = 0.75}, 1) + end +}) + minetest.register_node("gltf:frog", { description = "glTF frog, but it's a node", diff --git a/irr/include/IAnimatedMesh.h b/irr/include/IAnimatedMesh.h index 80b3bc3ca..2a1c1f4b1 100644 --- a/irr/include/IAnimatedMesh.h +++ b/irr/include/IAnimatedMesh.h @@ -19,11 +19,8 @@ irr::scene::SMeshBuffer etc. */ class IAnimatedMesh : public IMesh { public: - //! Gets the frame count of the animated mesh. - /** Note that the play-time is usually getFrameCount()-1 as it stops as soon as the last frame-key is reached. - \return The amount of frames. If the amount is 1, - it is a static, non animated mesh. */ - virtual u32 getFrameCount() const = 0; + //! Gets the maximum frame number, 0 if the mesh is static. + virtual f32 getMaxFrameNumber() const = 0; //! Gets the animation speed of the animated mesh. /** \return The number of frames per second to play the @@ -39,19 +36,10 @@ public: virtual void setAnimationSpeed(f32 fps) = 0; //! Returns the IMesh interface for a frame. - /** \param frame: Frame number as zero based index. The maximum - frame number is getFrameCount() - 1; - \param detailLevel: Level of detail. 0 is the lowest, 255 the - highest level of detail. Most meshes will ignore the detail level. - \param startFrameLoop: Because some animated meshes (.MD2) are - blended between 2 static frames, and maybe animated in a loop, - the startFrameLoop and the endFrameLoop have to be defined, to - prevent the animation to be blended between frames which are - outside of this loop. - If startFrameLoop and endFrameLoop are both -1, they are ignored. - \param endFrameLoop: see startFrameLoop. - \return Returns the animated mesh based on a detail level. */ - virtual IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) = 0; + /** \param frame: Frame number, >= 0, <= getMaxFrameNumber() + Linear interpolation is used if this is between two frames. + \return Returns the animated mesh for the given frame */ + virtual IMesh *getMesh(f32 frame) = 0; //! Returns the type of the animated mesh. /** In most cases it is not necessary to use this method. diff --git a/irr/include/IAnimatedMeshSceneNode.h b/irr/include/IAnimatedMeshSceneNode.h index 65fdaaadf..8f9f6d661 100644 --- a/irr/include/IAnimatedMeshSceneNode.h +++ b/irr/include/IAnimatedMeshSceneNode.h @@ -63,7 +63,7 @@ public: virtual void setCurrentFrame(f32 frame) = 0; //! Sets the frame numbers between the animation is looped. - /** The default is 0 to getFrameCount()-1 of the mesh. + /** The default is 0 to getMaxFrameNumber() of the mesh. Number of played frames is end-start. It interpolates toward the last frame but stops when it is reached. It does not interpolate back to start even when looping. @@ -71,7 +71,7 @@ public: \param begin: Start frame number of the loop. \param end: End frame number of the loop. \return True if successful, false if not. */ - virtual bool setFrameLoop(s32 begin, s32 end) = 0; + virtual bool setFrameLoop(f32 begin, f32 end) = 0; //! Sets the speed with which the animation is played. /** \param framesPerSecond: Frames per second played. */ @@ -108,9 +108,9 @@ public: //! Returns the currently displayed frame number. virtual f32 getFrameNr() const = 0; //! Returns the current start frame number. - virtual s32 getStartFrame() const = 0; + virtual f32 getStartFrame() const = 0; //! Returns the current end frame number. - virtual s32 getEndFrame() const = 0; + virtual f32 getEndFrame() const = 0; //! Sets looping mode which is on by default. /** If set to false, animations will not be played looped. */ diff --git a/irr/include/SAnimatedMesh.h b/irr/include/SAnimatedMesh.h index 8fe14b41f..dd7306633 100644 --- a/irr/include/SAnimatedMesh.h +++ b/irr/include/SAnimatedMesh.h @@ -36,11 +36,9 @@ struct SAnimatedMesh final : public IAnimatedMesh mesh->drop(); } - //! Gets the frame count of the animated mesh. - /** \return Amount of frames. If the amount is 1, it is a static, non animated mesh. */ - u32 getFrameCount() const override + f32 getMaxFrameNumber() const override { - return static_cast(Meshes.size()); + return static_cast(Meshes.size() - 1); } //! Gets the default animation speed of the animated mesh. @@ -59,19 +57,14 @@ struct SAnimatedMesh final : public IAnimatedMesh } //! Returns the IMesh interface for a frame. - /** \param frame: Frame number as zero based index. The maximum frame number is - getFrameCount() - 1; - \param detailLevel: Level of detail. 0 is the lowest, - 255 the highest level of detail. Most meshes will ignore the detail level. - \param startFrameLoop: start frame - \param endFrameLoop: end frame - \return The animated mesh based on a detail level. */ - IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) override + /** \param frame: Frame number as zero based index. + \return The animated mesh based for the given frame */ + IMesh *getMesh(f32 frame) override { if (Meshes.empty()) - return 0; + return nullptr; - return Meshes[frame]; + return Meshes[static_cast(frame)]; } //! adds a Mesh diff --git a/irr/include/vector2d.h b/irr/include/vector2d.h index caf69e6be..182965295 100644 --- a/irr/include/vector2d.h +++ b/irr/include/vector2d.h @@ -38,6 +38,12 @@ public: explicit constexpr vector2d(const std::array &arr) : X(arr[0]), Y(arr[1]) {} + template + constexpr static vector2d from(const vector2d &other) + { + return {static_cast(other.X), static_cast(other.Y)}; + } + // operators vector2d operator-() const { return vector2d(-X, -Y); } diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index 295d408f3..ba8bc3b78 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -16,6 +16,7 @@ #include "IAnimatedMesh.h" #include "IFileSystem.h" #include "quaternion.h" +#include namespace irr { @@ -80,7 +81,7 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs) } if (StartFrame == EndFrame) { - CurrentFrameNr = (f32)StartFrame; // Support for non animated meshes + CurrentFrameNr = StartFrame; // Support for non animated meshes } else if (Looping) { // play animation looped CurrentFrameNr += timeMs * FramesPerSecond; @@ -89,26 +90,26 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs) // the last frame must be identical to first one with our current solution. if (FramesPerSecond > 0.f) { // forwards... if (CurrentFrameNr > EndFrame) - CurrentFrameNr = StartFrame + fmodf(CurrentFrameNr - StartFrame, (f32)(EndFrame - StartFrame)); + CurrentFrameNr = StartFrame + fmodf(CurrentFrameNr - StartFrame, EndFrame - StartFrame); } else // backwards... { if (CurrentFrameNr < StartFrame) - CurrentFrameNr = EndFrame - fmodf(EndFrame - CurrentFrameNr, (f32)(EndFrame - StartFrame)); + CurrentFrameNr = EndFrame - fmodf(EndFrame - CurrentFrameNr, EndFrame - StartFrame); } } else { // play animation non looped CurrentFrameNr += timeMs * FramesPerSecond; if (FramesPerSecond > 0.f) { // forwards... - if (CurrentFrameNr > (f32)EndFrame) { - CurrentFrameNr = (f32)EndFrame; + if (CurrentFrameNr > EndFrame) { + CurrentFrameNr = EndFrame; if (LoopCallBack) LoopCallBack->OnAnimationEnd(this); } } else // backwards... { - if (CurrentFrameNr < (f32)StartFrame) { - CurrentFrameNr = (f32)StartFrame; + if (CurrentFrameNr < StartFrame) { + CurrentFrameNr = StartFrame; if (LoopCallBack) LoopCallBack->OnAnimationEnd(this); } @@ -159,9 +160,7 @@ void CAnimatedMeshSceneNode::OnRegisterSceneNode() IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame() { if (Mesh->getMeshType() != EAMT_SKINNED) { - s32 frameNr = (s32)getFrameNr(); - s32 frameBlend = (s32)(core::fract(getFrameNr()) * 1000.f); - return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame); + return Mesh->getMesh(getFrameNr()); } else { // As multiple scene nodes may be sharing the same skinned mesh, we have to // re-animate it every frame to ensure that this node gets the mesh that it needs. @@ -331,33 +330,33 @@ void CAnimatedMeshSceneNode::render() } //! Returns the current start frame number. -s32 CAnimatedMeshSceneNode::getStartFrame() const +f32 CAnimatedMeshSceneNode::getStartFrame() const { return StartFrame; } //! Returns the current start frame number. -s32 CAnimatedMeshSceneNode::getEndFrame() const +f32 CAnimatedMeshSceneNode::getEndFrame() const { return EndFrame; } //! sets the frames between the animation is looped. //! the default is 0 - MaximalFrameCount of the mesh. -bool CAnimatedMeshSceneNode::setFrameLoop(s32 begin, s32 end) +bool CAnimatedMeshSceneNode::setFrameLoop(f32 begin, f32 end) { - const s32 maxFrameCount = Mesh->getFrameCount() - 1; + const f32 maxFrame = Mesh->getMaxFrameNumber(); if (end < begin) { - StartFrame = core::s32_clamp(end, 0, maxFrameCount); - EndFrame = core::s32_clamp(begin, StartFrame, maxFrameCount); + StartFrame = std::clamp(end, 0, maxFrame); + EndFrame = std::clamp(begin, StartFrame, maxFrame); } else { - StartFrame = core::s32_clamp(begin, 0, maxFrameCount); - EndFrame = core::s32_clamp(end, StartFrame, maxFrameCount); + StartFrame = std::clamp(begin, 0, maxFrame); + EndFrame = std::clamp(end, StartFrame, maxFrame); } if (FramesPerSecond < 0) - setCurrentFrame((f32)EndFrame); + setCurrentFrame(EndFrame); else - setCurrentFrame((f32)StartFrame); + setCurrentFrame(StartFrame); return true; } @@ -532,7 +531,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh *mesh) // get materials and bounding box Box = Mesh->getBoundingBox(); - IMesh *m = Mesh->getMesh(0, 0); + IMesh *m = Mesh->getMesh(0); if (m) { Materials.clear(); Materials.reallocate(m->getMeshBufferCount()); @@ -554,7 +553,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh *mesh) // get start and begin time setAnimationSpeed(Mesh->getAnimationSpeed()); // NOTE: This had been commented out (but not removed!) in r3526. Which caused meshloader-values for speed to be ignored unless users specified explicitly. Missing a test-case where this could go wrong so I put the code back in. - setFrameLoop(0, Mesh->getFrameCount() - 1); + setFrameLoop(0, Mesh->getMaxFrameNumber()); } //! updates the absolute position based on the relative and the parents position diff --git a/irr/src/CAnimatedMeshSceneNode.h b/irr/src/CAnimatedMeshSceneNode.h index 0364ab527..e45edca86 100644 --- a/irr/src/CAnimatedMeshSceneNode.h +++ b/irr/src/CAnimatedMeshSceneNode.h @@ -45,7 +45,7 @@ public: //! sets the frames between the animation is looped. //! the default is 0 - MaximalFrameCount of the mesh. //! NOTE: setMesh will also change this value and set it to the full range of animations of the mesh - bool setFrameLoop(s32 begin, s32 end) override; + bool setFrameLoop(f32 begin, f32 end) override; //! Sets looping mode which is on by default. If set to false, //! animations will not be looped. @@ -93,9 +93,9 @@ public: //! Returns the current displayed frame number. f32 getFrameNr() const override; //! Returns the current start frame number. - s32 getStartFrame() const override; + f32 getStartFrame() const override; //! Returns the current end frame number. - s32 getEndFrame() const override; + f32 getEndFrame() const override; //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. /* In this way it is possible to change the materials a mesh causing all mesh scene nodes @@ -148,8 +148,8 @@ private: core::aabbox3d Box; IAnimatedMesh *Mesh; - s32 StartFrame; - s32 EndFrame; + f32 StartFrame; + f32 EndFrame; f32 FramesPerSecond; f32 CurrentFrameNr; diff --git a/irr/src/CMeshManipulator.cpp b/irr/src/CMeshManipulator.cpp index 2c9d05336..67b22a07e 100644 --- a/irr/src/CMeshManipulator.cpp +++ b/irr/src/CMeshManipulator.cpp @@ -193,7 +193,7 @@ s32 CMeshManipulator::getPolyCount(scene::IMesh *mesh) const //! Returns amount of polygons in mesh. s32 CMeshManipulator::getPolyCount(scene::IAnimatedMesh *mesh) const { - if (mesh && mesh->getFrameCount() != 0) + if (mesh && mesh->getMaxFrameNumber() != 0) return getPolyCount(mesh->getMesh(0)); return 0; diff --git a/irr/src/CSkinnedMesh.cpp b/irr/src/CSkinnedMesh.cpp index 56ef3efe1..875fd8e7e 100644 --- a/irr/src/CSkinnedMesh.cpp +++ b/irr/src/CSkinnedMesh.cpp @@ -111,11 +111,9 @@ CSkinnedMesh::~CSkinnedMesh() } } -//! returns the amount of frames in milliseconds. -//! If the amount is 1, it is a static (=non animated) mesh. -u32 CSkinnedMesh::getFrameCount() const +f32 CSkinnedMesh::getMaxFrameNumber() const { - return core::floor32(EndFrame + 1.f); + return EndFrame; } //! Gets the default animation speed of the animated mesh. @@ -133,14 +131,14 @@ void CSkinnedMesh::setAnimationSpeed(f32 fps) FramesPerSecond = fps; } -//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. -IMesh *CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +//! returns the animated mesh based +IMesh *CSkinnedMesh::getMesh(f32 frame) { // animate(frame,startFrameLoop, endFrameLoop); if (frame == -1) return this; - animateMesh((f32)frame, 1.0f); + animateMesh(frame, 1.0f); skinMesh(); return this; } diff --git a/irr/src/CSkinnedMesh.h b/irr/src/CSkinnedMesh.h index 4b4c5e3b7..1be6ee7bc 100644 --- a/irr/src/CSkinnedMesh.h +++ b/irr/src/CSkinnedMesh.h @@ -27,8 +27,8 @@ public: //! destructor virtual ~CSkinnedMesh(); - //! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh. - u32 getFrameCount() const override; + //! If the duration is 0, it is a static (=non animated) mesh. + f32 getMaxFrameNumber() const override; //! Gets the default animation speed of the animated mesh. /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ @@ -39,8 +39,8 @@ public: The actual speed is set in the scene node the mesh is instantiated in.*/ void setAnimationSpeed(f32 fps) override; - //! returns the animated mesh based on a detail level (which is ignored) - IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) override; + //! returns the animated mesh for the given frame + IMesh *getMesh(f32) override; //! Animates this mesh's joints based on frame input //! blend: {0-old position, 1-New position} diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index adec70983..c8acb3875 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1052,7 +1052,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) walking = true; } - v2s32 new_anim = v2s32(0,0); + v2f new_anim(0,0); bool allow_update = false; // increase speed if using fast or flying fast @@ -1799,10 +1799,9 @@ void GenericCAO::processMessage(const std::string &data) phys.speed_walk = override_speed_walk; } } else if (cmd == AO_CMD_SET_ANIMATION) { - // TODO: change frames send as v2s32 value v2f range = readV2F32(is); if (!m_is_local_player) { - m_animation_range = v2s32((s32)range.X, (s32)range.Y); + m_animation_range = range; m_animation_speed = readF32(is); m_animation_blend = readF32(is); // these are sent inverted so we get true when the server sends nothing @@ -1812,7 +1811,7 @@ void GenericCAO::processMessage(const std::string &data) LocalPlayer *player = m_env->getLocalPlayer(); if(player->last_animation == LocalPlayerAnimation::NO_ANIM) { - m_animation_range = v2s32((s32)range.X, (s32)range.Y); + m_animation_range = range; m_animation_speed = readF32(is); m_animation_blend = readF32(is); // these are sent inverted so we get true when the server sends nothing diff --git a/src/client/content_cao.h b/src/client/content_cao.h index 3fdf01bc7..d138e39c3 100644 --- a/src/client/content_cao.h +++ b/src/client/content_cao.h @@ -99,7 +99,7 @@ private: v2s16 m_tx_basepos; bool m_initial_tx_basepos_set = false; bool m_tx_select_horiz_by_yawpitch = false; - v2s32 m_animation_range; + v2f m_animation_range; float m_animation_speed = 15.0f; float m_animation_blend = 0.0f; bool m_animation_loop = true; diff --git a/src/gui/guiScene.cpp b/src/gui/guiScene.cpp index 33310fe35..06784cd6e 100644 --- a/src/gui/guiScene.cpp +++ b/src/gui/guiScene.cpp @@ -157,7 +157,7 @@ void GUIScene::setStyles(const std::array &sty /** * Sets the frame loop range for the mesh */ -void GUIScene::setFrameLoop(s32 begin, s32 end) +void GUIScene::setFrameLoop(f32 begin, f32 end) { if (m_mesh->getStartFrame() != begin || m_mesh->getEndFrame() != end) m_mesh->setFrameLoop(begin, end); diff --git a/src/gui/guiScene.h b/src/gui/guiScene.h index 0f5f3a891..0634669f7 100644 --- a/src/gui/guiScene.h +++ b/src/gui/guiScene.h @@ -36,7 +36,7 @@ public: scene::IAnimatedMeshSceneNode *setMesh(scene::IAnimatedMesh *mesh = nullptr); void setTexture(u32 idx, video::ITexture *texture); void setBackgroundColor(const video::SColor &color) noexcept { m_bgcolor = color; }; - void setFrameLoop(s32 begin, s32 end); + void setFrameLoop(f32 begin, f32 end); void setAnimationSpeed(f32 speed); void enableMouseControl(bool enable) noexcept { m_mouse_ctrl = enable; }; void setRotation(v2f rot) noexcept { m_custom_rot = rot; }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 725b6a5c7..373e39b4e 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/client.h" +#include "irr_v2d.h" #include "util/base64.h" #include "client/camera.h" #include "client/mesh_generator_thread.h" @@ -1516,11 +1517,15 @@ void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt) LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); - *pkt >> player->local_animations[0]; - *pkt >> player->local_animations[1]; - *pkt >> player->local_animations[2]; - *pkt >> player->local_animations[3]; - *pkt >> player->local_animation_speed; + for (int i = 0; i < 4; ++i) { + if (getProtoVersion() >= 46) { + *pkt >> player->local_animations[i]; + } else { + v2s32 local_animation; + *pkt >> local_animation; + player->local_animations[i] = v2f::from(local_animation); + } + } player->last_animation = LocalPlayerAnimation::NO_ANIM; } diff --git a/src/network/networkprotocol.cpp b/src/network/networkprotocol.cpp index 38b958d24..40f8acef1 100644 --- a/src/network/networkprotocol.cpp +++ b/src/network/networkprotocol.cpp @@ -57,6 +57,7 @@ old servers. Rename TOCLIENT_DEATHSCREEN to TOCLIENT_DEATHSCREEN_LEGACY Rename TOSERVER_RESPAWN to TOSERVER_RESPAWN_LEGACY + Support float animation frame numbers in TOCLIENT_LOCAL_PLAYER_ANIMATIONS [scheduled bump for 5.10.0] */ diff --git a/src/player.h b/src/player.h index 972a04e02..c729f98a0 100644 --- a/src/player.h +++ b/src/player.h @@ -203,7 +203,7 @@ public: f32 movement_liquid_sink; f32 movement_gravity; - v2s32 local_animations[4]; + v2f local_animations[4]; float local_animation_speed; std::string inventory_formspec; diff --git a/src/remoteplayer.h b/src/remoteplayer.h index 4923c307d..cbfc80d91 100644 --- a/src/remoteplayer.h +++ b/src/remoteplayer.h @@ -113,14 +113,14 @@ public: inline void setModified(const bool x) { m_dirty = x; } - void setLocalAnimations(v2s32 frames[4], float frame_speed) + void setLocalAnimations(v2f frames[4], float frame_speed) { for (int i = 0; i < 4; i++) local_animations[i] = frames[i]; local_animation_speed = frame_speed; } - void getLocalAnimations(v2s32 *frames, float *frame_speed) + void getLocalAnimations(v2f *frames, float *frame_speed) { for (int i = 0; i < 4; i++) frames[i] = local_animations[i]; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index b9ea0a4e4..ae863502f 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -433,10 +433,10 @@ int ObjectRef::l_set_local_animation(lua_State *L) if (player == nullptr) return 0; - v2s32 frames[4]; + v2f frames[4]; for (int i=0;i<4;i++) { if (!lua_isnil(L, 2+1)) - frames[i] = read_v2s32(L, 2+i); + frames[i] = read_v2f(L, 2+i); } float frame_speed = readParam(L, 6, 30.0f); @@ -453,12 +453,12 @@ int ObjectRef::l_get_local_animation(lua_State *L) if (player == nullptr) return 0; - v2s32 frames[4]; + v2f frames[4]; float frame_speed; player->getLocalAnimations(frames, &frame_speed); - for (const v2s32 &frame : frames) { - push_v2s32(L, frame); + for (const v2f &frame : frames) { + push_v2f(L, frame); } lua_pushnumber(L, frame_speed); diff --git a/src/server.cpp b/src/server.cpp index 7634e2433..405af63ef 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "irr_v2d.h" #include "network/connection.h" #include "network/networkprotocol.h" #include "network/serveropcodes.h" @@ -1987,14 +1988,21 @@ void Server::SendPlayerFov(session_t peer_id) Send(&pkt); } -void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4], +void Server::SendLocalPlayerAnimations(session_t peer_id, v2f animation_frames[4], f32 animation_speed) { NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0, peer_id); - pkt << animation_frames[0] << animation_frames[1] << animation_frames[2] - << animation_frames[3] << animation_speed; + for (int i = 0; i < 4; ++i) { + if (m_clients.getProtocolVersion(peer_id) >= 46) { + pkt << animation_frames[i]; + } else { + pkt << v2s32::from(animation_frames[i]); + } + } + + pkt << animation_speed; Send(&pkt); } @@ -3424,7 +3432,7 @@ Address Server::getPeerAddress(session_t peer_id) } void Server::setLocalPlayerAnimations(RemotePlayer *player, - v2s32 animation_frames[4], f32 frame_speed) + v2f animation_frames[4], f32 frame_speed) { sanity_check(player); player->setLocalAnimations(animation_frames, frame_speed); diff --git a/src/server.h b/src/server.h index 57b543c11..0318ec6f6 100644 --- a/src/server.h +++ b/src/server.h @@ -344,7 +344,7 @@ public: Address getPeerAddress(session_t peer_id); - void setLocalPlayerAnimations(RemotePlayer *player, v2s32 animation_frames[4], + void setLocalPlayerAnimations(RemotePlayer *player, v2f animation_frames[4], f32 frame_speed); void setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third, v3f third_front); @@ -501,7 +501,7 @@ private: virtual void SendChatMessage(session_t peer_id, const ChatMessage &message); void SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed); - void SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4], + void SendLocalPlayerAnimations(session_t peer_id, v2f animation_frames[4], f32 animation_speed); void SendEyeOffset(session_t peer_id, v3f first, v3f third, v3f third_front); void SendPlayerPrivileges(session_t peer_id);