Server: avoid re-use of recent ParticleSpawner and Sound IDs (#14045)

This improves the reliability when removing and re-adding handles quickly.
Looping through the entire ID range avoids collisions caused by any race condition.
This commit is contained in:
SmallJoker 2023-11-29 21:10:19 +01:00 committed by GitHub
parent d6a8b546e4
commit a7e5456099
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 25 additions and 16 deletions

@ -2171,12 +2171,18 @@ void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
inline s32 Server::nextSoundId() inline s32 Server::nextSoundId()
{ {
s32 ret = m_next_sound_id; s32 free_id = m_playing_sounds_id_last_used;
if (m_next_sound_id == INT32_MAX) while (free_id == 0 || m_playing_sounds.find(free_id) != m_playing_sounds.end()) {
m_next_sound_id = 0; // signed overflow is undefined if (free_id == INT32_MAX)
free_id = 0; // signed overflow is undefined
else else
m_next_sound_id++; free_id++;
return ret;
if (free_id == m_playing_sounds_id_last_used)
return 0;
}
m_playing_sounds_id_last_used = free_id;
return free_id;
} }
s32 Server::playSound(ServerPlayingSound &params, bool ephemeral) s32 Server::playSound(ServerPlayingSound &params, bool ephemeral)
@ -2232,6 +2238,8 @@ s32 Server::playSound(ServerPlayingSound &params, bool ephemeral)
// old clients will still use this, so pick a reserved ID (-1) // old clients will still use this, so pick a reserved ID (-1)
const s32 id = ephemeral ? -1 : nextSoundId(); const s32 id = ephemeral ? -1 : nextSoundId();
if (id == 0)
return 0;
float gain = params.gain * params.spec.gain; float gain = params.gain * params.spec.gain;
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0); NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);

@ -695,7 +695,7 @@ private:
Sounds Sounds
*/ */
std::unordered_map<s32, ServerPlayingSound> m_playing_sounds; std::unordered_map<s32, ServerPlayingSound> m_playing_sounds;
s32 m_next_sound_id = 0; // positive values only s32 m_playing_sounds_id_last_used = 0; // positive values only
s32 nextSoundId(); s32 nextSoundId();
ModStorageDatabase *m_mod_storage_database = nullptr; ModStorageDatabase *m_mod_storage_database = nullptr;

@ -1637,16 +1637,16 @@ u32 ServerEnvironment::addParticleSpawner(float exptime)
// Timers with lifetime 0 do not expire // Timers with lifetime 0 do not expire
float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY; float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY;
u32 id = 0; u32 free_id = m_particle_spawners_id_last_used;
for (;;) { // look for unused particlespawner id while (free_id == 0 || m_particle_spawners.find(free_id) != m_particle_spawners.end()) {
id++; if (free_id == m_particle_spawners_id_last_used)
std::unordered_map<u32, float>::iterator f = m_particle_spawners.find(id); return 0; // full
if (f == m_particle_spawners.end()) { free_id++;
m_particle_spawners[id] = time;
break;
} }
}
return id; m_particle_spawners_id_last_used = free_id;
m_particle_spawners[free_id] = time;
return free_id;
} }
u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id) u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)

@ -512,6 +512,7 @@ private:
// Particles // Particles
IntervalLimiter m_particle_management_interval; IntervalLimiter m_particle_management_interval;
std::unordered_map<u32, float> m_particle_spawners; std::unordered_map<u32, float> m_particle_spawners;
u32 m_particle_spawners_id_last_used = 0;
std::unordered_map<u32, u16> m_particle_spawner_attachments; std::unordered_map<u32, u16> m_particle_spawner_attachments;
// Environment metrics // Environment metrics