From c607bee19e286165fd497d57d2bb2b8ac5986f36 Mon Sep 17 00:00:00 2001
From: sfan5 <sfan5@live.de>
Date: Sun, 4 Sep 2022 16:22:12 +0200
Subject: [PATCH] Allow looped animation to be used safely with old clients

fixes #12657
---
 src/client/particles.cpp |  1 +
 src/particles.cpp        |  4 ++--
 src/tileanimation.cpp    | 14 ++++++++++----
 src/tileanimation.h      |  4 ++--
 4 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/src/client/particles.cpp b/src/client/particles.cpp
index 95d3c2021..85baee7cd 100644
--- a/src/client/particles.cpp
+++ b/src/client/particles.cpp
@@ -555,6 +555,7 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius,
 
 	// synchronize animation length with particle life if desired
 	if (pp.animation.type != TAT_NONE) {
+		// FIXME: this should be moved into a TileAnimationParams class method
 		if (pp.animation.type == TAT_VERTICAL_FRAMES &&
 			pp.animation.vertical_frames.length < 0) {
 			auto& a = pp.animation.vertical_frames;
diff --git a/src/particles.cpp b/src/particles.cpp
index 19b3418b7..e495ecd03 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -127,7 +127,7 @@ void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const
 	os << serializeString32(texture.string);
 	writeU8(os, vertical);
 	writeU8(os, collision_removal);
-	animation.serialize(os, 6); /* NOT the protocol ver */
+	animation.serialize(os, protocol_ver);
 	writeU8(os, glow);
 	writeU8(os, object_collision);
 	writeU16(os, node.param0);
@@ -160,7 +160,7 @@ void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver)
 	texture.string     = deSerializeString32(is);
 	vertical           = readU8(is);
 	collision_removal  = readU8(is);
-	animation.deSerialize(is, 6); /* NOT the protocol ver */
+	animation.deSerialize(is, protocol_ver);
 	glow               = readU8(is);
 	object_collision   = readU8(is);
 
diff --git a/src/tileanimation.cpp b/src/tileanimation.cpp
index a79a36e57..025d27d91 100644
--- a/src/tileanimation.cpp
+++ b/src/tileanimation.cpp
@@ -19,21 +19,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "tileanimation.h"
 #include "util/serialize.h"
 
-void TileAnimationParams::serialize(std::ostream &os, u16 protocol_version) const
+void TileAnimationParams::serialize(std::ostream &os, u16 protocol_ver) const
 {
+	// The particle code overloads the length parameter so that negative numbers
+	// indicate an extra feature which old clients don't understand (crash).
+	// In hindsight it would have been better to use an extra parameter for this
+	// but we're stuck with this now.
+	const bool need_abs = protocol_ver < 40;
+
 	writeU8(os, type);
 	if (type == TAT_VERTICAL_FRAMES) {
 		writeU16(os, vertical_frames.aspect_w);
 		writeU16(os, vertical_frames.aspect_h);
-		writeF32(os, vertical_frames.length);
+		writeF32(os, need_abs ? fabs(vertical_frames.length) : vertical_frames.length);
 	} else if (type == TAT_SHEET_2D) {
 		writeU8(os, sheet_2d.frames_w);
 		writeU8(os, sheet_2d.frames_h);
-		writeF32(os, sheet_2d.frame_length);
+		writeF32(os, need_abs ? fabs(sheet_2d.frame_length) : sheet_2d.frame_length);
 	}
 }
 
-void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version)
+void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_ver)
 {
 	type = (TileAnimationType) readU8(is);
 
diff --git a/src/tileanimation.h b/src/tileanimation.h
index 0449de0b8..45b91655e 100644
--- a/src/tileanimation.h
+++ b/src/tileanimation.h
@@ -50,8 +50,8 @@ struct TileAnimationParams
 		} sheet_2d;
 	};
 
-	void serialize(std::ostream &os, u16 protocol_version) const;
-	void deSerialize(std::istream &is, u16 protocol_version);
+	void serialize(std::ostream &os, u16 protocol_ver) const;
+	void deSerialize(std::istream &is, u16 protocol_ver);
 	void determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms,
 			v2u32 *frame_size) const;
 	void getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const;