mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Add exclude_player to particle spawners
This commit is contained in:
		@@ -49,6 +49,7 @@ core.features = {
 | 
			
		||||
	httpfetch_additional_methods = true,
 | 
			
		||||
	object_guids = true,
 | 
			
		||||
	on_timer_four_args = true,
 | 
			
		||||
	particlespawner_exclude_player = true,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function core.has_feature(arg)
 | 
			
		||||
 
 | 
			
		||||
@@ -5843,6 +5843,8 @@ Utilities
 | 
			
		||||
      object_guids = true,
 | 
			
		||||
      -- The NodeTimer `on_timer` callback is passed additional `node` and `timeout` args (5.14.0)
 | 
			
		||||
      on_timer_four_args = true,
 | 
			
		||||
      -- `ParticleSpawner` definition supports `exclude_player` field (5.14.0)
 | 
			
		||||
      particlespawner_exclude_player = true,
 | 
			
		||||
  }
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
@@ -7471,6 +7473,7 @@ Particles
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
* `core.add_particle(particle definition)`
 | 
			
		||||
    * Spawn a single particle
 | 
			
		||||
    * Deprecated: `core.add_particle(pos, velocity, acceleration,
 | 
			
		||||
      expirationtime, size, collisiondetection, texture, playername)`
 | 
			
		||||
 | 
			
		||||
@@ -11487,6 +11490,9 @@ Used by `core.add_particle`.
 | 
			
		||||
    playername = "singleplayer",
 | 
			
		||||
    -- Optional, if specified spawns particle only on the player's client
 | 
			
		||||
 | 
			
		||||
    -- Note that `exclude_player` is not supported here. You can use a single-use
 | 
			
		||||
    -- particlespawner if needed.
 | 
			
		||||
 | 
			
		||||
    animation = {Tile Animation definition},
 | 
			
		||||
    -- Optional, specifies how to animate the particle texture
 | 
			
		||||
 | 
			
		||||
@@ -11550,6 +11556,9 @@ will be ignored.
 | 
			
		||||
    -- If time is 0 spawner has infinite lifespan and spawns the `amount` on
 | 
			
		||||
    -- a per-second basis.
 | 
			
		||||
 | 
			
		||||
    size = 1,
 | 
			
		||||
    -- Size of the particle.
 | 
			
		||||
 | 
			
		||||
    collisiondetection = false,
 | 
			
		||||
    -- If true collide with `walkable` nodes and, depending on the
 | 
			
		||||
    -- `object_collision` field, objects too.
 | 
			
		||||
@@ -11576,7 +11585,12 @@ will be ignored.
 | 
			
		||||
    -- following section.
 | 
			
		||||
 | 
			
		||||
    playername = "singleplayer",
 | 
			
		||||
    -- Optional, if specified spawns particles only on the player's client
 | 
			
		||||
    -- Optional, if specified spawns particles only for this player
 | 
			
		||||
    -- Can't be used together with `exclude_player`.
 | 
			
		||||
 | 
			
		||||
    exclude_player = "singleplayer",
 | 
			
		||||
    -- Optional, if specified spawns particles not for this player
 | 
			
		||||
    -- Added in v5.14.0. Can't be used together with `playername`.
 | 
			
		||||
 | 
			
		||||
    animation = {Tile Animation definition},
 | 
			
		||||
    -- Optional, specifies how to animate the particles' texture
 | 
			
		||||
 
 | 
			
		||||
@@ -157,7 +157,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
 | 
			
		||||
	// Get parameters
 | 
			
		||||
	ParticleSpawnerParameters p;
 | 
			
		||||
	ServerActiveObject *attached = NULL;
 | 
			
		||||
	std::string playername;
 | 
			
		||||
	std::string playername, not_playername;
 | 
			
		||||
 | 
			
		||||
	using namespace ParticleParamTypes;
 | 
			
		||||
	if (lua_gettop(L) > 1) //deprecated
 | 
			
		||||
@@ -257,7 +257,6 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
 | 
			
		||||
		lua_pop(L, 1);
 | 
			
		||||
 | 
			
		||||
		p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
 | 
			
		||||
		playername = getstringfield_default(L, 1, "playername", "");
 | 
			
		||||
		p.glow = getintfield_default(L, 1, "glow", p.glow);
 | 
			
		||||
 | 
			
		||||
		lua_getfield(L, 1, "texpool");
 | 
			
		||||
@@ -279,12 +278,16 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
 | 
			
		||||
		lua_pop(L, 1);
 | 
			
		||||
 | 
			
		||||
		p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
 | 
			
		||||
 | 
			
		||||
		// meta parameters
 | 
			
		||||
		playername = getstringfield_default(L, 1, "playername", "");
 | 
			
		||||
		not_playername = getstringfield_default(L, 1, "exclude_player", "");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (p.time < 0)
 | 
			
		||||
		throw LuaError("particle spawner 'time' must be >= 0");
 | 
			
		||||
 | 
			
		||||
	u32 id = getServer(L)->addParticleSpawner(p, attached, playername);
 | 
			
		||||
	u32 id = getServer(L)->addParticleSpawner(p, attached, playername, not_playername);
 | 
			
		||||
	lua_pushnumber(L, id);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -1646,45 +1646,61 @@ void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
 | 
			
		||||
	Send(&pkt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adds a ParticleSpawner on peer with peer_id
 | 
			
		||||
void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
 | 
			
		||||
void Server::SendAddParticleSpawner(const std::string &to_player,
 | 
			
		||||
	const std::string &exclude_player,
 | 
			
		||||
	const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
 | 
			
		||||
{
 | 
			
		||||
	static thread_local const float radius =
 | 
			
		||||
			g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
 | 
			
		||||
	const float radius_sq = radius * radius;
 | 
			
		||||
 | 
			
		||||
	if (peer_id == PEER_ID_INEXISTENT) {
 | 
			
		||||
		std::vector<session_t> clients = m_clients.getClientIDs();
 | 
			
		||||
		const v3f pos = (
 | 
			
		||||
			p.pos.start.min.val +
 | 
			
		||||
			p.pos.start.max.val +
 | 
			
		||||
			p.pos.end.min.val +
 | 
			
		||||
			p.pos.end.max.val
 | 
			
		||||
		) / 4.0f * BS;
 | 
			
		||||
		const float radius_sq = radius * radius;
 | 
			
		||||
		/* Don't send short-lived spawners to distant players.
 | 
			
		||||
		 * This could be replaced with proper tracking at some point.
 | 
			
		||||
		 * A lifetime of 0 means that the spawner exists forever.*/
 | 
			
		||||
		const bool distance_check = !attached_id && p.time <= 1.0f && p.time != 0.0f;
 | 
			
		||||
	// Average position where particles would spawn (approximate)
 | 
			
		||||
	const v3f pos = (
 | 
			
		||||
		p.pos.start.min.val +
 | 
			
		||||
		p.pos.start.max.val +
 | 
			
		||||
		p.pos.end.min.val +
 | 
			
		||||
		p.pos.end.max.val
 | 
			
		||||
	) / 4.0f * BS;
 | 
			
		||||
	/* Don't send short-lived spawners to distant players.
 | 
			
		||||
	 * This could be replaced with proper tracking at some point.
 | 
			
		||||
	 * A lifetime of 0 means that the spawner exists forever. */
 | 
			
		||||
	const bool distance_check = !attached_id && p.time <= 1.0f && p.time != 0.0f;
 | 
			
		||||
 | 
			
		||||
		for (const session_t client_id : clients) {
 | 
			
		||||
			RemotePlayer *player = m_env->getPlayer(client_id);
 | 
			
		||||
			if (!player)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			if (distance_check) {
 | 
			
		||||
				PlayerSAO *sao = player->getPlayerSAO();
 | 
			
		||||
				if (!sao)
 | 
			
		||||
					continue;
 | 
			
		||||
				if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
 | 
			
		||||
					continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			SendAddParticleSpawner(client_id, player->protocol_version,
 | 
			
		||||
				p, attached_id, id);
 | 
			
		||||
	const auto &consider_player = [&] (RemotePlayer *player) {
 | 
			
		||||
		if (distance_check) {
 | 
			
		||||
			PlayerSAO *sao = player->getPlayerSAO();
 | 
			
		||||
			if (!sao)
 | 
			
		||||
				return;
 | 
			
		||||
			if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
 | 
			
		||||
				return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SendAddParticleSpawner(player->getPeerId(), player->protocol_version,
 | 
			
		||||
			p, attached_id, id);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Send to one -or- all (except one)
 | 
			
		||||
	if (!to_player.empty()) {
 | 
			
		||||
		RemotePlayer *player = m_env->getPlayer(to_player);
 | 
			
		||||
		if (player)
 | 
			
		||||
			consider_player(player);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	std::vector<session_t> clients = m_clients.getClientIDs();
 | 
			
		||||
	for (const session_t client_id : clients) {
 | 
			
		||||
		RemotePlayer *player = m_env->getPlayer(client_id);
 | 
			
		||||
		if (!player)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (!exclude_player.empty() && exclude_player == player->getName())
 | 
			
		||||
			continue;
 | 
			
		||||
		consider_player(player);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
 | 
			
		||||
	const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
 | 
			
		||||
{
 | 
			
		||||
	assert(peer_id != PEER_ID_INEXISTENT);
 | 
			
		||||
	assert(protocol_version != 0);
 | 
			
		||||
 | 
			
		||||
	NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
 | 
			
		||||
@@ -3619,22 +3635,12 @@ void Server::spawnParticle(const std::string &playername,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
 | 
			
		||||
	ServerActiveObject *attached, const std::string &playername)
 | 
			
		||||
	ServerActiveObject *attached, const std::string &to_player,
 | 
			
		||||
	const std::string &exclude_player)
 | 
			
		||||
{
 | 
			
		||||
	// m_env will be NULL if the server is initializing
 | 
			
		||||
	if (!m_env)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	session_t peer_id = PEER_ID_INEXISTENT;
 | 
			
		||||
	u16 proto_ver = 0;
 | 
			
		||||
	if (!playername.empty()) {
 | 
			
		||||
		RemotePlayer *player = m_env->getPlayer(playername.c_str());
 | 
			
		||||
		if (!player)
 | 
			
		||||
			return -1;
 | 
			
		||||
		peer_id = player->getPeerId();
 | 
			
		||||
		proto_ver = player->protocol_version;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u16 attached_id = attached ? attached->getId() : 0;
 | 
			
		||||
 | 
			
		||||
	u32 id;
 | 
			
		||||
@@ -3643,13 +3649,12 @@ u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
 | 
			
		||||
	else
 | 
			
		||||
		id = m_env->addParticleSpawner(p.time, attached_id);
 | 
			
		||||
 | 
			
		||||
	SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
 | 
			
		||||
	SendAddParticleSpawner(to_player, exclude_player, p, attached_id, id);
 | 
			
		||||
	return id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Server::deleteParticleSpawner(const std::string &playername, u32 id)
 | 
			
		||||
{
 | 
			
		||||
	// m_env will be NULL if the server is initializing
 | 
			
		||||
	if (!m_env)
 | 
			
		||||
		throw ServerError("Can't delete particle spawners during initialisation!");
 | 
			
		||||
 | 
			
		||||
@@ -3661,7 +3666,11 @@ void Server::deleteParticleSpawner(const std::string &playername, u32 id)
 | 
			
		||||
		peer_id = player->getPeerId();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// FIXME: we don't track which client still knows about this spawner, so
 | 
			
		||||
	// just deleting it entirely is problematic!
 | 
			
		||||
	// We also don't check if the ID is even in use. FAIL!
 | 
			
		||||
	m_env->deleteParticleSpawner(id);
 | 
			
		||||
 | 
			
		||||
	SendDeleteParticleSpawner(peer_id, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -291,7 +291,8 @@ public:
 | 
			
		||||
		const ParticleParameters &p);
 | 
			
		||||
 | 
			
		||||
	u32 addParticleSpawner(const ParticleSpawnerParameters &p,
 | 
			
		||||
		ServerActiveObject *attached, const std::string &playername);
 | 
			
		||||
		ServerActiveObject *attached, const std::string &to_player,
 | 
			
		||||
		const std::string &exclude_player);
 | 
			
		||||
 | 
			
		||||
	void deleteParticleSpawner(const std::string &playername, u32 id);
 | 
			
		||||
 | 
			
		||||
@@ -593,7 +594,11 @@ private:
 | 
			
		||||
			const std::unordered_set<std::string> &tosend);
 | 
			
		||||
	void stepPendingDynMediaCallbacks(float dtime);
 | 
			
		||||
 | 
			
		||||
	// Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
 | 
			
		||||
	/// @brief send particle spawner to a selection of clients
 | 
			
		||||
	void SendAddParticleSpawner(const std::string &to_player,
 | 
			
		||||
		const std::string &exclude_player,
 | 
			
		||||
		const ParticleSpawnerParameters &p, u16 attached_id, u32 id);
 | 
			
		||||
	/// @brief send particle spawner to one client (internal)
 | 
			
		||||
	void SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
 | 
			
		||||
		const ParticleSpawnerParameters &p, u16 attached_id, u32 id);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user