From 660fa516bfe774c77947c47a97154d6f069f414d Mon Sep 17 00:00:00 2001
From: MirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Date: Sat, 21 Feb 2015 23:38:53 +0200
Subject: [PATCH] Fix some issues with animations, and allow non-looped
 animations to be defined

---
 doc/lua_api.txt                 |  4 ++--
 src/content_cao.cpp             | 18 ++++++++++++++++--
 src/content_cao.h               |  1 +
 src/content_sao.cpp             | 26 ++++++++++++++++++--------
 src/content_sao.h               | 10 ++++++----
 src/genericobject.cpp           |  4 +++-
 src/genericobject.h             |  2 +-
 src/script/lua_api/l_object.cpp | 13 +++++++++----
 src/script/lua_api/l_object.h   |  2 +-
 src/serverobject.h              |  4 ++--
 10 files changed, 59 insertions(+), 25 deletions(-)

diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index a65c53c1a..d2505284a 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -2434,8 +2434,8 @@ This is basically a reference to a C++ `ServerActiveObject`
 * `set_wielded_item(item)`: replaces the wielded item, returns `true` if successful
 * `set_armor_groups({group1=rating, group2=rating, ...})`
 * `get_armor_groups()`: returns a table with the armor group ratings
-* `set_animation({x=1,y=1}, frame_speed=15, frame_blend=0)`
-* `get_animation()`: returns range, frame_speed and frame_blend
+* `set_animation({x=1,y=1}, frame_speed=15, frame_blend=0, frame_loop=true)`
+* `get_animation()`: returns range, frame_speed, frame_blend and frame_loop
 * `set_attach(parent, bone, position, rotation)`
     * `bone`: string
     * `position`: `{x=num, y=num, z=num}` (relative)
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index 01be1422c..d38cb892a 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -565,6 +565,7 @@ GenericCAO::GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
 		m_animation_range(v2s32(0,0)),
 		m_animation_speed(15),
 		m_animation_blend(0),
+		m_animation_loop(true),
 		m_bone_position(std::map<std::string, core::vector2d<v3f> >()),
 		m_attachment_bone(""),
 		m_attachment_position(v3f(0,0,0)),
@@ -1465,9 +1466,18 @@ void GenericCAO::updateAnimation()
 {
 	if(m_animated_meshnode == NULL)
 		return;
-	m_animated_meshnode->setFrameLoop(m_animation_range.X, m_animation_range.Y);
-	m_animated_meshnode->setAnimationSpeed(m_animation_speed);
+
+	if (m_animated_meshnode->getStartFrame() != m_animation_range.X ||
+		m_animated_meshnode->getEndFrame() != m_animation_range.Y)
+			m_animated_meshnode->setFrameLoop(m_animation_range.X, m_animation_range.Y);
+	if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed)
+		m_animated_meshnode->setAnimationSpeed(m_animation_speed);
 	m_animated_meshnode->setTransitionTime(m_animation_blend);
+// Requires Irrlicht 1.8 or greater
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR > 1
+	if (m_animated_meshnode->getLoopMode() != m_animation_loop)
+		m_animated_meshnode->setLoopMode(m_animation_loop);
+#endif
 }
 
 void GenericCAO::updateBonePosition()
@@ -1633,6 +1643,8 @@ void GenericCAO::processMessage(const std::string &data)
 			m_animation_range = v2s32((s32)range.X, (s32)range.Y);
 			m_animation_speed = readF1000(is);
 			m_animation_blend = readF1000(is);
+			// these are sent inverted so we get true when the server sends nothing
+			m_animation_loop = !readU8(is);
 			updateAnimation();
 		} else {
 			LocalPlayer *player = m_env->getLocalPlayer();
@@ -1641,6 +1653,8 @@ void GenericCAO::processMessage(const std::string &data)
 				m_animation_range = v2s32((s32)range.X, (s32)range.Y);
 				m_animation_speed = readF1000(is);
 				m_animation_blend = readF1000(is);
+				// these are sent inverted so we get true when the server sends nothing
+				m_animation_loop = !readU8(is);
 			}
 			// update animation only if local animations present
 			// and received animation is unknown (except idle animation)
diff --git a/src/content_cao.h b/src/content_cao.h
index 58c373389..1e526d1cd 100644
--- a/src/content_cao.h
+++ b/src/content_cao.h
@@ -86,6 +86,7 @@ class GenericCAO : public ClientActiveObject
 	v2s32 m_animation_range;
 	int m_animation_speed;
 	int m_animation_blend;
+	bool m_animation_loop;
 	std::map<std::string, core::vector2d<v3f> > m_bone_position; // stores position and rotation for each bone name
 	std::string m_attachment_bone;
 	v3f m_attachment_position;
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 984d2ffa3..386b7e070 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -136,6 +136,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
 	m_armor_groups_sent(false),
 	m_animation_speed(0),
 	m_animation_blend(0),
+	m_animation_loop(true),
 	m_animation_sent(false),
 	m_bone_position_sent(false),
 	m_attachment_parent_id(0),
@@ -324,7 +325,8 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
 
 	if(m_animation_sent == false){
 		m_animation_sent = true;
-		std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
+		std::string str = gob_cmd_update_animation(
+			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
 		// create message and add to list
 		ActiveObjectMessage aom(getId(), true, str);
 		m_messages_out.push(aom);
@@ -366,7 +368,8 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
 		writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
 		os<<serializeLongString(getPropertyPacket()); // message 1
 		os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
-		os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
+		os<<serializeLongString(gob_cmd_update_animation(
+			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
 		for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
 			os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
 		}
@@ -533,19 +536,21 @@ ItemGroupList LuaEntitySAO::getArmorGroups()
 	return m_armor_groups;
 }
 
-void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
+void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
 {
 	m_animation_range = frame_range;
 	m_animation_speed = frame_speed;
 	m_animation_blend = frame_blend;
+	m_animation_loop = frame_loop;
 	m_animation_sent = false;
 }
 
-void LuaEntitySAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend)
+void LuaEntitySAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop)
 {
 	*frame_range = m_animation_range;
 	*frame_speed = m_animation_speed;
 	*frame_blend = m_animation_blend;
+	*frame_loop = m_animation_loop;
 }
 
 void LuaEntitySAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
@@ -733,6 +738,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
 	m_is_singleplayer(is_singleplayer),
 	m_animation_speed(0),
 	m_animation_blend(0),
+	m_animation_loop(true),
 	m_animation_sent(false),
 	m_bone_position_sent(false),
 	m_attachment_parent_id(0),
@@ -828,7 +834,8 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
 		writeU8(os, 6 + m_bone_position.size()); // number of messages stuffed in here
 		os<<serializeLongString(getPropertyPacket()); // message 1
 		os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
-		os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
+		os<<serializeLongString(gob_cmd_update_animation(
+			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
 		for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
 			os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
 		}
@@ -967,7 +974,8 @@ void PlayerSAO::step(float dtime, bool send_recommended)
 
 	if(m_animation_sent == false){
 		m_animation_sent = true;
-		std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
+		std::string str = gob_cmd_update_animation(
+			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
 		// create message and add to list
 		ActiveObjectMessage aom(getId(), true, str);
 		m_messages_out.push(aom);
@@ -1166,20 +1174,22 @@ ItemGroupList PlayerSAO::getArmorGroups()
 	return m_armor_groups;
 }
 
-void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
+void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
 {
 	// store these so they can be updated to clients
 	m_animation_range = frame_range;
 	m_animation_speed = frame_speed;
 	m_animation_blend = frame_blend;
+	m_animation_loop = frame_loop;
 	m_animation_sent = false;
 }
 
-void PlayerSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend)
+void PlayerSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop)
 {
 	*frame_range = m_animation_range;
 	*frame_speed = m_animation_speed;
 	*frame_blend = m_animation_blend;
+	*frame_loop = m_animation_loop;
 }
 
 void PlayerSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
diff --git a/src/content_sao.h b/src/content_sao.h
index 241788066..f61566665 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -59,8 +59,8 @@ class LuaEntitySAO : public ServerActiveObject
 	s16 getHP() const;
 	void setArmorGroups(const ItemGroupList &armor_groups);
 	ItemGroupList getArmorGroups();
-	void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
-	void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend);
+	void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop);
+	void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop);
 	void setBonePosition(const std::string &bone, v3f position, v3f rotation);
 	void getBonePosition(const std::string &bone, v3f *position, v3f *rotation);
 	void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
@@ -106,6 +106,7 @@ class LuaEntitySAO : public ServerActiveObject
 	v2f m_animation_range;
 	float m_animation_speed;
 	float m_animation_blend;
+	bool m_animation_loop;
 	bool m_animation_sent;
 
 	std::map<std::string, core::vector2d<v3f> > m_bone_position;
@@ -197,8 +198,8 @@ class PlayerSAO : public ServerActiveObject
 	void setBreath(u16 breath);
 	void setArmorGroups(const ItemGroupList &armor_groups);
 	ItemGroupList getArmorGroups();
-	void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
-	void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend);
+	void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop);
+	void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop);
 	void setBonePosition(const std::string &bone, v3f position, v3f rotation);
 	void getBonePosition(const std::string &bone, v3f *position, v3f *rotation);
 	void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
@@ -312,6 +313,7 @@ class PlayerSAO : public ServerActiveObject
 	v2f m_animation_range;
 	float m_animation_speed;
 	float m_animation_blend;
+	bool m_animation_loop;
 	bool m_animation_sent;
 
 	std::map<std::string, core::vector2d<v3f> > m_bone_position; // Stores position and rotation for each bone name
diff --git a/src/genericobject.cpp b/src/genericobject.cpp
index 5daba55ed..90e8cf3d3 100644
--- a/src/genericobject.cpp
+++ b/src/genericobject.cpp
@@ -133,7 +133,7 @@ std::string gob_cmd_update_physics_override(float physics_override_speed, float
 	return os.str();
 }
 
-std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend)
+std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend, bool frame_loop)
 {
 	std::ostringstream os(std::ios::binary);
 	// command 
@@ -142,6 +142,8 @@ std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_
 	writeV2F1000(os, frames);
 	writeF1000(os, frame_speed);
 	writeF1000(os, frame_blend);
+	// these are sent inverted so we get true when the server sends nothing
+	writeU8(os, !frame_loop);
 	return os.str();
 }
 
diff --git a/src/genericobject.h b/src/genericobject.h
index b36a3830d..b92570831 100644
--- a/src/genericobject.h
+++ b/src/genericobject.h
@@ -69,7 +69,7 @@ std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups);
 std::string gob_cmd_update_physics_override(float physics_override_speed,
 		float physics_override_jump, float physics_override_gravity, bool sneak, bool sneak_glitch);
 
-std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend);
+std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend, bool frame_loop);
 
 std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation);
 
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index 48d054dcd..4b1cc39fb 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -449,7 +449,7 @@ int ObjectRef::l_get_physics_override(lua_State *L)
 	return 1;
 }
 
-// set_animation(self, frame_range, frame_speed, frame_blend)
+// set_animation(self, frame_range, frame_speed, frame_blend, frame_loop)
 int ObjectRef::l_set_animation(lua_State *L)
 {
 	NO_MAP_LOCK_REQUIRED;
@@ -466,7 +466,10 @@ int ObjectRef::l_set_animation(lua_State *L)
 	float frame_blend = 0;
 	if(!lua_isnil(L, 4))
 		frame_blend = lua_tonumber(L, 4);
-	co->setAnimation(frames, frame_speed, frame_blend);
+	bool frame_loop = true;
+	if(lua_isboolean(L, 5))
+		frame_loop = lua_toboolean(L, 5);
+	co->setAnimation(frames, frame_speed, frame_blend, frame_loop);
 	return 0;
 }
 
@@ -482,12 +485,14 @@ int ObjectRef::l_get_animation(lua_State *L)
 	v2f frames = v2f(1,1);
 	float frame_speed = 15;
 	float frame_blend = 0;
-	co->getAnimation(&frames, &frame_speed, &frame_blend);
+	bool frame_loop = true;
+	co->getAnimation(&frames, &frame_speed, &frame_blend, &frame_loop);
 
 	push_v2f(L, frames);
 	lua_pushnumber(L, frame_speed);
 	lua_pushnumber(L, frame_blend);
-	return 3;
+	lua_pushboolean(L, frame_loop);
+	return 4;
 }
 
 // set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed)
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index 02bb06ecc..9e4a62058 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -111,7 +111,7 @@ class ObjectRef : public ModApiBase {
 	// get_physics_override(self)
 	static int l_get_physics_override(lua_State *L);
 
-	// set_animation(self, frame_range, frame_speed, frame_blend)
+	// set_animation(self, frame_range, frame_speed, frame_blend, frame_loop)
 	static int l_set_animation(lua_State *L);
 
 	// get_animation(self)
diff --git a/src/serverobject.h b/src/serverobject.h
index 5de1071d1..7204fe3ae 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -151,9 +151,9 @@ class ServerActiveObject : public ActiveObject
 	{ return ItemGroupList(); }
 	virtual void setPhysicsOverride(float physics_override_speed, float physics_override_jump, float physics_override_gravity)
 	{}
-	virtual void setAnimation(v2f frames, float frame_speed, float frame_blend)
+	virtual void setAnimation(v2f frames, float frame_speed, float frame_blend, bool frame_loop)
 	{}
-	virtual void getAnimation(v2f *frames, float *frame_speed, float *frame_blend)
+	virtual void getAnimation(v2f *frames, float *frame_speed, float *frame_blend, bool *frame_loop)
 	{}
 	virtual void setBonePosition(const std::string &bone, v3f position, v3f rotation)
 	{}
-- 
GitLab