mirror of
https://github.com/luanti-org/luanti.git
synced 2025-09-15 18:57:08 +00:00
Add exclude_player to particle spawners
This commit is contained in:
parent
b6a23b1bcc
commit
f714ac0611
5 changed files with 82 additions and 50 deletions
|
@ -49,6 +49,7 @@ core.features = {
|
||||||
httpfetch_additional_methods = true,
|
httpfetch_additional_methods = true,
|
||||||
object_guids = true,
|
object_guids = true,
|
||||||
on_timer_four_args = true,
|
on_timer_four_args = true,
|
||||||
|
particlespawner_exclude_player = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
function core.has_feature(arg)
|
function core.has_feature(arg)
|
||||||
|
|
|
@ -5843,6 +5843,8 @@ Utilities
|
||||||
object_guids = true,
|
object_guids = true,
|
||||||
-- The NodeTimer `on_timer` callback is passed additional `node` and `timeout` args (5.14.0)
|
-- The NodeTimer `on_timer` callback is passed additional `node` and `timeout` args (5.14.0)
|
||||||
on_timer_four_args = true,
|
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)`
|
* `core.add_particle(particle definition)`
|
||||||
|
* Spawn a single particle
|
||||||
* Deprecated: `core.add_particle(pos, velocity, acceleration,
|
* Deprecated: `core.add_particle(pos, velocity, acceleration,
|
||||||
expirationtime, size, collisiondetection, texture, playername)`
|
expirationtime, size, collisiondetection, texture, playername)`
|
||||||
|
|
||||||
|
@ -11487,6 +11490,9 @@ Used by `core.add_particle`.
|
||||||
playername = "singleplayer",
|
playername = "singleplayer",
|
||||||
-- Optional, if specified spawns particle only on the player's client
|
-- 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},
|
animation = {Tile Animation definition},
|
||||||
-- Optional, specifies how to animate the particle texture
|
-- 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
|
-- If time is 0 spawner has infinite lifespan and spawns the `amount` on
|
||||||
-- a per-second basis.
|
-- a per-second basis.
|
||||||
|
|
||||||
|
size = 1,
|
||||||
|
-- Size of the particle.
|
||||||
|
|
||||||
collisiondetection = false,
|
collisiondetection = false,
|
||||||
-- If true collide with `walkable` nodes and, depending on the
|
-- If true collide with `walkable` nodes and, depending on the
|
||||||
-- `object_collision` field, objects too.
|
-- `object_collision` field, objects too.
|
||||||
|
@ -11576,7 +11585,12 @@ will be ignored.
|
||||||
-- following section.
|
-- following section.
|
||||||
|
|
||||||
playername = "singleplayer",
|
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},
|
animation = {Tile Animation definition},
|
||||||
-- Optional, specifies how to animate the particles' texture
|
-- Optional, specifies how to animate the particles' texture
|
||||||
|
|
|
@ -157,7 +157,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
|
||||||
// Get parameters
|
// Get parameters
|
||||||
ParticleSpawnerParameters p;
|
ParticleSpawnerParameters p;
|
||||||
ServerActiveObject *attached = NULL;
|
ServerActiveObject *attached = NULL;
|
||||||
std::string playername;
|
std::string playername, not_playername;
|
||||||
|
|
||||||
using namespace ParticleParamTypes;
|
using namespace ParticleParamTypes;
|
||||||
if (lua_gettop(L) > 1) //deprecated
|
if (lua_gettop(L) > 1) //deprecated
|
||||||
|
@ -257,7 +257,6 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
|
p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
|
||||||
playername = getstringfield_default(L, 1, "playername", "");
|
|
||||||
p.glow = getintfield_default(L, 1, "glow", p.glow);
|
p.glow = getintfield_default(L, 1, "glow", p.glow);
|
||||||
|
|
||||||
lua_getfield(L, 1, "texpool");
|
lua_getfield(L, 1, "texpool");
|
||||||
|
@ -279,12 +278,16 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
|
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)
|
if (p.time < 0)
|
||||||
throw LuaError("particle spawner 'time' must be >= 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);
|
lua_pushnumber(L, id);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -1646,45 +1646,61 @@ void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
|
||||||
Send(&pkt);
|
Send(&pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a ParticleSpawner on peer with peer_id
|
void Server::SendAddParticleSpawner(const std::string &to_player,
|
||||||
void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
|
const std::string &exclude_player,
|
||||||
const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
|
const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
|
||||||
{
|
{
|
||||||
static thread_local const float radius =
|
static thread_local const float radius =
|
||||||
g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
|
g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
|
||||||
|
const float radius_sq = radius * radius;
|
||||||
|
|
||||||
if (peer_id == PEER_ID_INEXISTENT) {
|
// Average position where particles would spawn (approximate)
|
||||||
std::vector<session_t> clients = m_clients.getClientIDs();
|
|
||||||
const v3f pos = (
|
const v3f pos = (
|
||||||
p.pos.start.min.val +
|
p.pos.start.min.val +
|
||||||
p.pos.start.max.val +
|
p.pos.start.max.val +
|
||||||
p.pos.end.min.val +
|
p.pos.end.min.val +
|
||||||
p.pos.end.max.val
|
p.pos.end.max.val
|
||||||
) / 4.0f * BS;
|
) / 4.0f * BS;
|
||||||
const float radius_sq = radius * radius;
|
|
||||||
/* Don't send short-lived spawners to distant players.
|
/* Don't send short-lived spawners to distant players.
|
||||||
* This could be replaced with proper tracking at some point.
|
* 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 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) {
|
for (const session_t client_id : clients) {
|
||||||
RemotePlayer *player = m_env->getPlayer(client_id);
|
RemotePlayer *player = m_env->getPlayer(client_id);
|
||||||
if (!player)
|
if (!player)
|
||||||
continue;
|
continue;
|
||||||
|
if (!exclude_player.empty() && exclude_player == player->getName())
|
||||||
if (distance_check) {
|
|
||||||
PlayerSAO *sao = player->getPlayerSAO();
|
|
||||||
if (!sao)
|
|
||||||
continue;
|
|
||||||
if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
|
|
||||||
continue;
|
continue;
|
||||||
|
consider_player(player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendAddParticleSpawner(client_id, player->protocol_version,
|
void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
|
||||||
p, attached_id, id);
|
const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
|
||||||
}
|
{
|
||||||
return;
|
assert(peer_id != PEER_ID_INEXISTENT);
|
||||||
}
|
|
||||||
assert(protocol_version != 0);
|
assert(protocol_version != 0);
|
||||||
|
|
||||||
NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
|
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,
|
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)
|
if (!m_env)
|
||||||
return -1;
|
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;
|
u16 attached_id = attached ? attached->getId() : 0;
|
||||||
|
|
||||||
u32 id;
|
u32 id;
|
||||||
|
@ -3643,13 +3649,12 @@ u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
|
||||||
else
|
else
|
||||||
id = m_env->addParticleSpawner(p.time, attached_id);
|
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;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::deleteParticleSpawner(const std::string &playername, u32 id)
|
void Server::deleteParticleSpawner(const std::string &playername, u32 id)
|
||||||
{
|
{
|
||||||
// m_env will be NULL if the server is initializing
|
|
||||||
if (!m_env)
|
if (!m_env)
|
||||||
throw ServerError("Can't delete particle spawners during initialisation!");
|
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();
|
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);
|
m_env->deleteParticleSpawner(id);
|
||||||
|
|
||||||
SendDeleteParticleSpawner(peer_id, id);
|
SendDeleteParticleSpawner(peer_id, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,7 +291,8 @@ public:
|
||||||
const ParticleParameters &p);
|
const ParticleParameters &p);
|
||||||
|
|
||||||
u32 addParticleSpawner(const ParticleSpawnerParameters &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);
|
void deleteParticleSpawner(const std::string &playername, u32 id);
|
||||||
|
|
||||||
|
@ -593,7 +594,11 @@ private:
|
||||||
const std::unordered_set<std::string> &tosend);
|
const std::unordered_set<std::string> &tosend);
|
||||||
void stepPendingDynMediaCallbacks(float dtime);
|
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,
|
void SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
|
||||||
const ParticleSpawnerParameters &p, u16 attached_id, u32 id);
|
const ParticleSpawnerParameters &p, u16 attached_id, u32 id);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue