forked from Mirrorlandia_minetest/minetest
Improve core.sound_play with ephemeral sounds and player exclusion
This commit is contained in:
parent
ea5e231959
commit
ace3c76112
@ -826,7 +826,7 @@ Examples of sound parameter tables:
|
||||
gain = 1.0, -- default
|
||||
loop = true,
|
||||
}
|
||||
-- Play in a location
|
||||
-- Play at a location
|
||||
{
|
||||
pos = {x = 1, y = 2, z = 3},
|
||||
gain = 1.0, -- default
|
||||
@ -839,13 +839,22 @@ Examples of sound parameter tables:
|
||||
max_hear_distance = 32, -- default, uses an euclidean metric
|
||||
loop = true,
|
||||
}
|
||||
-- Play at a location, heard by anyone *but* the given player
|
||||
{
|
||||
pos = {x = 32, y = 0, z = 100},
|
||||
max_hear_distance = 40,
|
||||
exclude_player = name,
|
||||
}
|
||||
|
||||
Looped sounds must either be connected to an object or played locationless to
|
||||
one player using `to_player = name,`.
|
||||
one player using `to_player = name`.
|
||||
|
||||
A positional sound will only be heard by players that are within
|
||||
`max_hear_distance` of the sound position, at the start of the sound.
|
||||
|
||||
`exclude_player = name` can be applied to locationless, positional and object-
|
||||
bound sounds to exclude a single player from hearing them.
|
||||
|
||||
`SimpleSoundSpec`
|
||||
-----------------
|
||||
|
||||
@ -4929,10 +4938,15 @@ Defaults for the `on_punch` and `on_dig` node definition callbacks
|
||||
Sounds
|
||||
------
|
||||
|
||||
* `minetest.sound_play(spec, parameters)`: returns a handle
|
||||
* `minetest.sound_play(spec, parameters, [ephemeral])`: returns a handle
|
||||
* `spec` is a `SimpleSoundSpec`
|
||||
* `parameters` is a sound parameter table
|
||||
* `ephemeral` is a boolean (default: false)
|
||||
Ephemeral sounds will not return a handle and can't be stopped or faded.
|
||||
It is recommend to use this for short sounds that happen in response to
|
||||
player actions (e.g. door closing).
|
||||
* `minetest.sound_stop(handle)`
|
||||
* `handle` is a handle returned by `minetest.sound_play`
|
||||
* `minetest.sound_fade(handle, step, gain)`
|
||||
* `handle` is a handle returned by `minetest.sound_play`
|
||||
* `step` determines how fast a sound will fade.
|
||||
|
@ -1106,7 +1106,7 @@ void Client::sendRemovedSounds(std::vector<s32> &soundList)
|
||||
|
||||
pkt << (u16) (server_ids & 0xFFFF);
|
||||
|
||||
for (int sound_id : soundList)
|
||||
for (s32 sound_id : soundList)
|
||||
pkt << sound_id;
|
||||
|
||||
Send(&pkt);
|
||||
|
@ -561,7 +561,7 @@ private:
|
||||
std::unordered_map<s32, int> m_sounds_server_to_client;
|
||||
// And the other way!
|
||||
std::unordered_map<int, s32> m_sounds_client_to_server;
|
||||
// And relations to objects
|
||||
// Relation of client id to object id
|
||||
std::unordered_map<int, u16> m_sounds_to_objects;
|
||||
|
||||
// Map server hud ids to client hud ids
|
||||
|
@ -778,6 +778,7 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
||||
[25 + len] bool loop
|
||||
[26 + len] f32 fade
|
||||
[30 + len] f32 pitch
|
||||
[34 + len] bool ephemeral
|
||||
*/
|
||||
|
||||
s32 server_id;
|
||||
@ -790,12 +791,14 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
||||
bool loop;
|
||||
float fade = 0.0f;
|
||||
float pitch = 1.0f;
|
||||
bool ephemeral = false;
|
||||
|
||||
*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
|
||||
|
||||
try {
|
||||
*pkt >> fade;
|
||||
*pkt >> pitch;
|
||||
*pkt >> ephemeral;
|
||||
} catch (PacketError &e) {};
|
||||
|
||||
// Start playing
|
||||
@ -813,7 +816,6 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
||||
if (cao)
|
||||
pos = cao->getPosition();
|
||||
client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
|
||||
// TODO: Set up sound to move with object
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -821,8 +823,11 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
||||
}
|
||||
|
||||
if (client_id != -1) {
|
||||
// for ephemeral sounds, server_id is not meaningful
|
||||
if (!ephemeral) {
|
||||
m_sounds_server_to_client[server_id] = client_id;
|
||||
m_sounds_client_to_server[client_id] = server_id;
|
||||
}
|
||||
if (object_id != 0)
|
||||
m_sounds_to_objects[client_id] = object_id;
|
||||
}
|
||||
|
@ -200,6 +200,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
Unknown inventory serialization fields no longer throw an error
|
||||
Mod-specific formspec version
|
||||
Player FOV override API
|
||||
"ephemeral" added to TOCLIENT_PLAY_SOUND
|
||||
*/
|
||||
|
||||
#define LATEST_PROTOCOL_VERSION 38
|
||||
@ -450,6 +451,7 @@ enum ToClientCommand
|
||||
s32[3] pos_nodes*10000
|
||||
u16 object_id
|
||||
u8 loop (bool)
|
||||
u8 ephemeral (bool)
|
||||
*/
|
||||
|
||||
TOCLIENT_STOP_SOUND = 0x40,
|
||||
|
@ -1019,6 +1019,7 @@ void read_server_sound_params(lua_State *L, int index,
|
||||
params.max_hear_distance = BS*getfloatfield_default(L, index,
|
||||
"max_hear_distance", params.max_hear_distance/BS);
|
||||
getboolfield(L, index, "loop", params.loop);
|
||||
getstringfield(L, index, "exclude_player", params.exclude_player);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +429,7 @@ int ModApiServer::l_get_worldpath(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// sound_play(spec, parameters)
|
||||
// sound_play(spec, parameters, [ephemeral])
|
||||
int ModApiServer::l_sound_play(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
@ -437,8 +437,14 @@ int ModApiServer::l_sound_play(lua_State *L)
|
||||
read_soundspec(L, 1, spec);
|
||||
ServerSoundParams params;
|
||||
read_server_sound_params(L, 2, params);
|
||||
bool ephemeral = lua_gettop(L) > 2 && readParam<bool>(L, 3);
|
||||
if (ephemeral) {
|
||||
getServer(L)->playSound(spec, params, true);
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
s32 handle = getServer(L)->playSound(spec, params);
|
||||
lua_pushinteger(L, handle);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -446,7 +452,7 @@ int ModApiServer::l_sound_play(lua_State *L)
|
||||
int ModApiServer::l_sound_stop(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
int handle = luaL_checkinteger(L, 1);
|
||||
s32 handle = luaL_checkinteger(L, 1);
|
||||
getServer(L)->stopSound(handle);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2013,8 +2013,18 @@ void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
|
||||
Send(&pkt);
|
||||
}
|
||||
|
||||
inline s32 Server::nextSoundId()
|
||||
{
|
||||
s32 ret = m_next_sound_id;
|
||||
if (m_next_sound_id == INT32_MAX)
|
||||
m_next_sound_id = 0; // signed overflow is undefined
|
||||
else
|
||||
m_next_sound_id++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 Server::playSound(const SimpleSoundSpec &spec,
|
||||
const ServerSoundParams ¶ms)
|
||||
const ServerSoundParams ¶ms, bool ephemeral)
|
||||
{
|
||||
// Find out initial position of sound
|
||||
bool pos_exists = false;
|
||||
@ -2025,7 +2035,7 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
|
||||
|
||||
// Filter destination clients
|
||||
std::vector<session_t> dst_clients;
|
||||
if(!params.to_player.empty()) {
|
||||
if (!params.to_player.empty()) {
|
||||
RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
|
||||
if(!player){
|
||||
infostream<<"Server::playSound: Player \""<<params.to_player
|
||||
@ -2045,6 +2055,9 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
|
||||
RemotePlayer *player = m_env->getPlayer(client_id);
|
||||
if (!player)
|
||||
continue;
|
||||
if (!params.exclude_player.empty() &&
|
||||
params.exclude_player == player->getName())
|
||||
continue;
|
||||
|
||||
PlayerSAO *sao = player->getPlayerSAO();
|
||||
if (!sao)
|
||||
@ -2063,27 +2076,32 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
|
||||
return -1;
|
||||
|
||||
// Create the sound
|
||||
s32 id = m_next_sound_id++;
|
||||
s32 id;
|
||||
ServerPlayingSound *psound = nullptr;
|
||||
if (ephemeral) {
|
||||
id = -1; // old clients will still use this, so pick a reserved ID
|
||||
} else {
|
||||
id = nextSoundId();
|
||||
// The sound will exist as a reference in m_playing_sounds
|
||||
m_playing_sounds[id] = ServerPlayingSound();
|
||||
ServerPlayingSound &psound = m_playing_sounds[id];
|
||||
psound.params = params;
|
||||
psound.spec = spec;
|
||||
psound = &m_playing_sounds[id];
|
||||
psound->params = params;
|
||||
psound->spec = spec;
|
||||
}
|
||||
|
||||
float gain = params.gain * spec.gain;
|
||||
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
|
||||
pkt << id << spec.name << gain
|
||||
<< (u8) params.type << pos << params.object
|
||||
<< params.loop << params.fade << params.pitch;
|
||||
<< params.loop << params.fade << params.pitch
|
||||
<< ephemeral;
|
||||
|
||||
// Backwards compability
|
||||
bool play_sound = gain > 0;
|
||||
bool as_reliable = !ephemeral;
|
||||
|
||||
for (const u16 dst_client : dst_clients) {
|
||||
if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
|
||||
psound.clients.insert(dst_client);
|
||||
m_clients.send(dst_client, 0, &pkt, true);
|
||||
}
|
||||
if (psound)
|
||||
psound->clients.insert(dst_client);
|
||||
m_clients.send(dst_client, 0, &pkt, as_reliable);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ struct ServerSoundParams
|
||||
v3f pos;
|
||||
u16 object = 0;
|
||||
std::string to_player = "";
|
||||
std::string exclude_player = "";
|
||||
|
||||
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
|
||||
};
|
||||
@ -209,7 +210,8 @@ public:
|
||||
|
||||
// Returns -1 if failed, sound handle on success
|
||||
// Envlock
|
||||
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
|
||||
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms,
|
||||
bool ephemeral=false);
|
||||
void stopSound(s32 handle);
|
||||
void fadeSound(s32 handle, float step, float gain);
|
||||
|
||||
@ -646,7 +648,8 @@ private:
|
||||
Sounds
|
||||
*/
|
||||
std::unordered_map<s32, ServerPlayingSound> m_playing_sounds;
|
||||
s32 m_next_sound_id = 0;
|
||||
s32 m_next_sound_id = 0; // positive values only
|
||||
s32 nextSoundId();
|
||||
|
||||
/*
|
||||
Detached inventories (behind m_env_mutex)
|
||||
|
Loading…
Reference in New Issue
Block a user