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
|
gain = 1.0, -- default
|
||||||
loop = true,
|
loop = true,
|
||||||
}
|
}
|
||||||
-- Play in a location
|
-- Play at a location
|
||||||
{
|
{
|
||||||
pos = {x = 1, y = 2, z = 3},
|
pos = {x = 1, y = 2, z = 3},
|
||||||
gain = 1.0, -- default
|
gain = 1.0, -- default
|
||||||
@ -839,13 +839,22 @@ Examples of sound parameter tables:
|
|||||||
max_hear_distance = 32, -- default, uses an euclidean metric
|
max_hear_distance = 32, -- default, uses an euclidean metric
|
||||||
loop = true,
|
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
|
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
|
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.
|
`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`
|
`SimpleSoundSpec`
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@ -4929,10 +4938,15 @@ Defaults for the `on_punch` and `on_dig` node definition callbacks
|
|||||||
Sounds
|
Sounds
|
||||||
------
|
------
|
||||||
|
|
||||||
* `minetest.sound_play(spec, parameters)`: returns a handle
|
* `minetest.sound_play(spec, parameters, [ephemeral])`: returns a handle
|
||||||
* `spec` is a `SimpleSoundSpec`
|
* `spec` is a `SimpleSoundSpec`
|
||||||
* `parameters` is a sound parameter table
|
* `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)`
|
* `minetest.sound_stop(handle)`
|
||||||
|
* `handle` is a handle returned by `minetest.sound_play`
|
||||||
* `minetest.sound_fade(handle, step, gain)`
|
* `minetest.sound_fade(handle, step, gain)`
|
||||||
* `handle` is a handle returned by `minetest.sound_play`
|
* `handle` is a handle returned by `minetest.sound_play`
|
||||||
* `step` determines how fast a sound will fade.
|
* `step` determines how fast a sound will fade.
|
||||||
|
@ -1106,7 +1106,7 @@ void Client::sendRemovedSounds(std::vector<s32> &soundList)
|
|||||||
|
|
||||||
pkt << (u16) (server_ids & 0xFFFF);
|
pkt << (u16) (server_ids & 0xFFFF);
|
||||||
|
|
||||||
for (int sound_id : soundList)
|
for (s32 sound_id : soundList)
|
||||||
pkt << sound_id;
|
pkt << sound_id;
|
||||||
|
|
||||||
Send(&pkt);
|
Send(&pkt);
|
||||||
|
@ -561,7 +561,7 @@ private:
|
|||||||
std::unordered_map<s32, int> m_sounds_server_to_client;
|
std::unordered_map<s32, int> m_sounds_server_to_client;
|
||||||
// And the other way!
|
// And the other way!
|
||||||
std::unordered_map<int, s32> m_sounds_client_to_server;
|
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;
|
std::unordered_map<int, u16> m_sounds_to_objects;
|
||||||
|
|
||||||
// Map server hud ids to client hud ids
|
// Map server hud ids to client hud ids
|
||||||
|
@ -778,6 +778,7 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
|||||||
[25 + len] bool loop
|
[25 + len] bool loop
|
||||||
[26 + len] f32 fade
|
[26 + len] f32 fade
|
||||||
[30 + len] f32 pitch
|
[30 + len] f32 pitch
|
||||||
|
[34 + len] bool ephemeral
|
||||||
*/
|
*/
|
||||||
|
|
||||||
s32 server_id;
|
s32 server_id;
|
||||||
@ -790,12 +791,14 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
|||||||
bool loop;
|
bool loop;
|
||||||
float fade = 0.0f;
|
float fade = 0.0f;
|
||||||
float pitch = 1.0f;
|
float pitch = 1.0f;
|
||||||
|
bool ephemeral = false;
|
||||||
|
|
||||||
*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
|
*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
*pkt >> fade;
|
*pkt >> fade;
|
||||||
*pkt >> pitch;
|
*pkt >> pitch;
|
||||||
|
*pkt >> ephemeral;
|
||||||
} catch (PacketError &e) {};
|
} catch (PacketError &e) {};
|
||||||
|
|
||||||
// Start playing
|
// Start playing
|
||||||
@ -813,7 +816,6 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
|||||||
if (cao)
|
if (cao)
|
||||||
pos = cao->getPosition();
|
pos = cao->getPosition();
|
||||||
client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
|
client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
|
||||||
// TODO: Set up sound to move with object
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -821,8 +823,11 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (client_id != -1) {
|
if (client_id != -1) {
|
||||||
m_sounds_server_to_client[server_id] = client_id;
|
// for ephemeral sounds, server_id is not meaningful
|
||||||
m_sounds_client_to_server[client_id] = server_id;
|
if (!ephemeral) {
|
||||||
|
m_sounds_server_to_client[server_id] = client_id;
|
||||||
|
m_sounds_client_to_server[client_id] = server_id;
|
||||||
|
}
|
||||||
if (object_id != 0)
|
if (object_id != 0)
|
||||||
m_sounds_to_objects[client_id] = object_id;
|
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
|
Unknown inventory serialization fields no longer throw an error
|
||||||
Mod-specific formspec version
|
Mod-specific formspec version
|
||||||
Player FOV override API
|
Player FOV override API
|
||||||
|
"ephemeral" added to TOCLIENT_PLAY_SOUND
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LATEST_PROTOCOL_VERSION 38
|
#define LATEST_PROTOCOL_VERSION 38
|
||||||
@ -450,6 +451,7 @@ enum ToClientCommand
|
|||||||
s32[3] pos_nodes*10000
|
s32[3] pos_nodes*10000
|
||||||
u16 object_id
|
u16 object_id
|
||||||
u8 loop (bool)
|
u8 loop (bool)
|
||||||
|
u8 ephemeral (bool)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TOCLIENT_STOP_SOUND = 0x40,
|
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,
|
params.max_hear_distance = BS*getfloatfield_default(L, index,
|
||||||
"max_hear_distance", params.max_hear_distance/BS);
|
"max_hear_distance", params.max_hear_distance/BS);
|
||||||
getboolfield(L, index, "loop", params.loop);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sound_play(spec, parameters)
|
// sound_play(spec, parameters, [ephemeral])
|
||||||
int ModApiServer::l_sound_play(lua_State *L)
|
int ModApiServer::l_sound_play(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
@ -437,8 +437,14 @@ int ModApiServer::l_sound_play(lua_State *L)
|
|||||||
read_soundspec(L, 1, spec);
|
read_soundspec(L, 1, spec);
|
||||||
ServerSoundParams params;
|
ServerSoundParams params;
|
||||||
read_server_sound_params(L, 2, params);
|
read_server_sound_params(L, 2, params);
|
||||||
s32 handle = getServer(L)->playSound(spec, params);
|
bool ephemeral = lua_gettop(L) > 2 && readParam<bool>(L, 3);
|
||||||
lua_pushinteger(L, handle);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +452,7 @@ int ModApiServer::l_sound_play(lua_State *L)
|
|||||||
int ModApiServer::l_sound_stop(lua_State *L)
|
int ModApiServer::l_sound_stop(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
int handle = luaL_checkinteger(L, 1);
|
s32 handle = luaL_checkinteger(L, 1);
|
||||||
getServer(L)->stopSound(handle);
|
getServer(L)->stopSound(handle);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2013,8 +2013,18 @@ void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
|
|||||||
Send(&pkt);
|
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,
|
s32 Server::playSound(const SimpleSoundSpec &spec,
|
||||||
const ServerSoundParams ¶ms)
|
const ServerSoundParams ¶ms, bool ephemeral)
|
||||||
{
|
{
|
||||||
// Find out initial position of sound
|
// Find out initial position of sound
|
||||||
bool pos_exists = false;
|
bool pos_exists = false;
|
||||||
@ -2025,7 +2035,7 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
|
|||||||
|
|
||||||
// Filter destination clients
|
// Filter destination clients
|
||||||
std::vector<session_t> dst_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());
|
RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
|
||||||
if(!player){
|
if(!player){
|
||||||
infostream<<"Server::playSound: Player \""<<params.to_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);
|
RemotePlayer *player = m_env->getPlayer(client_id);
|
||||||
if (!player)
|
if (!player)
|
||||||
continue;
|
continue;
|
||||||
|
if (!params.exclude_player.empty() &&
|
||||||
|
params.exclude_player == player->getName())
|
||||||
|
continue;
|
||||||
|
|
||||||
PlayerSAO *sao = player->getPlayerSAO();
|
PlayerSAO *sao = player->getPlayerSAO();
|
||||||
if (!sao)
|
if (!sao)
|
||||||
@ -2063,27 +2076,32 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// Create the sound
|
// Create the sound
|
||||||
s32 id = m_next_sound_id++;
|
s32 id;
|
||||||
// The sound will exist as a reference in m_playing_sounds
|
ServerPlayingSound *psound = nullptr;
|
||||||
m_playing_sounds[id] = ServerPlayingSound();
|
if (ephemeral) {
|
||||||
ServerPlayingSound &psound = m_playing_sounds[id];
|
id = -1; // old clients will still use this, so pick a reserved ID
|
||||||
psound.params = params;
|
} else {
|
||||||
psound.spec = spec;
|
id = nextSoundId();
|
||||||
|
// The sound will exist as a reference in m_playing_sounds
|
||||||
|
m_playing_sounds[id] = ServerPlayingSound();
|
||||||
|
psound = &m_playing_sounds[id];
|
||||||
|
psound->params = params;
|
||||||
|
psound->spec = spec;
|
||||||
|
}
|
||||||
|
|
||||||
float gain = params.gain * spec.gain;
|
float gain = params.gain * spec.gain;
|
||||||
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
|
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
|
||||||
pkt << id << spec.name << gain
|
pkt << id << spec.name << gain
|
||||||
<< (u8) params.type << pos << params.object
|
<< (u8) params.type << pos << params.object
|
||||||
<< params.loop << params.fade << params.pitch;
|
<< params.loop << params.fade << params.pitch
|
||||||
|
<< ephemeral;
|
||||||
|
|
||||||
// Backwards compability
|
bool as_reliable = !ephemeral;
|
||||||
bool play_sound = gain > 0;
|
|
||||||
|
|
||||||
for (const u16 dst_client : dst_clients) {
|
for (const u16 dst_client : dst_clients) {
|
||||||
if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
|
if (psound)
|
||||||
psound.clients.insert(dst_client);
|
psound->clients.insert(dst_client);
|
||||||
m_clients.send(dst_client, 0, &pkt, true);
|
m_clients.send(dst_client, 0, &pkt, as_reliable);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ struct ServerSoundParams
|
|||||||
v3f pos;
|
v3f pos;
|
||||||
u16 object = 0;
|
u16 object = 0;
|
||||||
std::string to_player = "";
|
std::string to_player = "";
|
||||||
|
std::string exclude_player = "";
|
||||||
|
|
||||||
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
|
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
|
||||||
};
|
};
|
||||||
@ -209,7 +210,8 @@ public:
|
|||||||
|
|
||||||
// Returns -1 if failed, sound handle on success
|
// Returns -1 if failed, sound handle on success
|
||||||
// Envlock
|
// 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 stopSound(s32 handle);
|
||||||
void fadeSound(s32 handle, float step, float gain);
|
void fadeSound(s32 handle, float step, float gain);
|
||||||
|
|
||||||
@ -646,7 +648,8 @@ 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;
|
s32 m_next_sound_id = 0; // positive values only
|
||||||
|
s32 nextSoundId();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Detached inventories (behind m_env_mutex)
|
Detached inventories (behind m_env_mutex)
|
||||||
|
Loading…
Reference in New Issue
Block a user