From 6278da296be13c1229bfce45c476119a1db9477f Mon Sep 17 00:00:00 2001
From: obneq <obbneq@gmail.com>
Date: Thu, 28 Apr 2016 01:58:09 +1000
Subject: [PATCH] Handle particle spawners in env and delete expired ids

Rebased by Zeno (2016-04-2016)
---
 src/environment.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++
 src/environment.h   |  7 +++++++
 src/server.cpp      | 25 ++++++++----------------
 src/server.h        |  6 +-----
 4 files changed, 62 insertions(+), 22 deletions(-)

diff --git a/src/environment.cpp b/src/environment.cpp
index 902e2bda4..413bc7ff1 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -50,6 +50,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:"
 
+// A number that is much smaller than the timeout for particle spawners should/could ever be
+#define PARTICLE_SPAWNER_NO_EXPIRY -1024.f
+
 Environment::Environment():
 	m_time_of_day_speed(0),
 	m_time_of_day(9000),
@@ -1544,6 +1547,49 @@ void ServerEnvironment::step(float dtime)
 		*/
 		removeRemovedObjects();
 	}
+
+	/*
+		Manage particle spawner expiration
+	*/
+	if (m_particle_management_interval.step(dtime, 1.0)) {
+		for (std::map<u32, float>::iterator i = m_particle_spawners.begin();
+				i != m_particle_spawners.end(); ) {
+			//non expiring spawners
+			if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) {
+				++i;
+				continue;
+			}
+
+			i->second -= 1.0f;
+			if (i->second <= 0.f)
+				m_particle_spawners.erase(i++);
+			else
+				++i;
+		}
+	}
+}
+
+u32 ServerEnvironment::addParticleSpawner(float exptime)
+{
+	// Timers with lifetime 0 do not expire
+	float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY;
+
+	u32 id = 0;
+	for (;;) { // look for unused particlespawner id
+		id++;
+		std::map<u32, float>::iterator f;
+		f = m_particle_spawners.find(id);
+		if (f == m_particle_spawners.end()) {
+			m_particle_spawners[id] = time;
+			break;
+		}
+	}
+	return id;
+}
+
+void ServerEnvironment::deleteParticleSpawner(u32 id)
+{
+	m_particle_spawners.erase(id);
 }
 
 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
diff --git a/src/environment.h b/src/environment.h
index 660c6f1bc..c6786faed 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -337,6 +337,9 @@ class ServerEnvironment : public Environment
 	// env_meta.txt doesn't exist (e.g. new world)
 	void loadDefaultMeta();
 
+	u32 addParticleSpawner(float exptime);
+	void deleteParticleSpawner(u32 id);
+
 	/*
 		External ActiveObject interface
 		-------------------------------------------
@@ -516,6 +519,10 @@ class ServerEnvironment : public Environment
 	// Estimate for general maximum lag as determined by server.
 	// Can raise to high values like 15s with eg. map generation mods.
 	float m_max_lag_estimate;
+
+	// Particles
+	IntervalLimiter m_particle_management_interval;
+	std::map<u32, float> m_particle_spawners;
 };
 
 #ifndef SERVER
diff --git a/src/server.cpp b/src/server.cpp
index 6c008a2a1..0aba2796c 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -3194,19 +3194,7 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
 		peer_id = player->peer_id;
 	}
 
-	u32 id = 0;
-	for(;;) // look for unused particlespawner id
-	{
-		id++;
-		if (std::find(m_particlespawner_ids.begin(),
-				m_particlespawner_ids.end(), id)
-				== m_particlespawner_ids.end())
-		{
-			m_particlespawner_ids.push_back(id);
-			break;
-		}
-	}
-
+	u32 id = m_env->addParticleSpawner(spawntime);
 	SendAddParticleSpawner(peer_id, amount, spawntime,
 		minpos, maxpos, minvel, maxvel, minacc, maxacc,
 		minexptime, maxexptime, minsize, maxsize,
@@ -3229,13 +3217,16 @@ void Server::deleteParticleSpawner(const std::string &playername, u32 id)
 		peer_id = player->peer_id;
 	}
 
-	m_particlespawner_ids.erase(
-			std::remove(m_particlespawner_ids.begin(),
-			m_particlespawner_ids.end(), id),
-			m_particlespawner_ids.end());
+	m_env->deleteParticleSpawner(id);
 	SendDeleteParticleSpawner(peer_id, id);
 }
 
+void Server::deleteParticleSpawnerAll(u32 id)
+{
+	m_env->deleteParticleSpawner(id);
+	SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
+}
+
 Inventory* Server::createDetachedInventory(const std::string &name)
 {
 	if(m_detached_inventories.count(name) > 0){
diff --git a/src/server.h b/src/server.h
index fd559ba14..daf51dee1 100644
--- a/src/server.h
+++ b/src/server.h
@@ -287,6 +287,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 		const std::string &playername);
 
 	void deleteParticleSpawner(const std::string &playername, u32 id);
+	void deleteParticleSpawnerAll(u32 id);
 
 	// Creates or resets inventory
 	Inventory* createDetachedInventory(const std::string &name);
@@ -662,11 +663,6 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 	// key = name
 	std::map<std::string, Inventory*> m_detached_inventories;
 
-	/*
-		Particles
-	*/
-	std::vector<u32> m_particlespawner_ids;
-
 	DISABLE_CLASS_COPY(Server);
 };
 
-- 
GitLab