mirror of
https://github.com/minetest/minetest.git
synced 2025-09-18 03:15:20 +02: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();
|
||||
// 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;
|
||||
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.*/
|
||||
* A lifetime of 0 means that the spawner exists forever. */
|
||||
const bool distance_check = !attached_id && p.time <= 1.0f && p.time != 0.0f;
|
||||
|
||||
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 (distance_check) {
|
||||
PlayerSAO *sao = player->getPlayerSAO();
|
||||
if (!sao)
|
||||
continue;
|
||||
if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
|
||||
if (!exclude_player.empty() && exclude_player == player->getName())
|
||||
continue;
|
||||
consider_player(player);
|
||||
}
|
||||
}
|
||||
|
||||
SendAddParticleSpawner(client_id, player->protocol_version,
|
||||
p, attached_id, id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
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