mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 01:53:45 +01:00
Lua API for playing sounds
This commit is contained in:
parent
06e93f8d95
commit
601d1936c9
@ -363,8 +363,40 @@ dump2(obj, name="_", dumped={})
|
||||
dump(obj, dumped={})
|
||||
^ Return object serialized as a string
|
||||
|
||||
Sounds
|
||||
-------
|
||||
Examples of sound parameter tables:
|
||||
-- Play locationless on all clients
|
||||
{
|
||||
gain = 1.0, -- default
|
||||
}
|
||||
-- Play locationless to a player
|
||||
{
|
||||
to_player = name,
|
||||
gain = 1.0, -- default
|
||||
}
|
||||
-- Play in a location
|
||||
{
|
||||
pos = {x=1,y=2,z=3},
|
||||
gain = 1.0, -- default
|
||||
max_hear_distance = 32, -- default
|
||||
}
|
||||
-- Play connected to an object, looped
|
||||
{
|
||||
object = <an ObjectRef>,
|
||||
gain = 1.0, -- default
|
||||
max_hear_distance = 32, -- default
|
||||
loop = true, -- only sounds connected to objects can be looped
|
||||
}
|
||||
|
||||
minetest namespace reference
|
||||
-----------------------------
|
||||
minetest.get_current_modname() -> string
|
||||
minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname"
|
||||
^ Useful for loading additional .lua modules or static data from mod
|
||||
minetest.get_worldpath(modname) -> eg. "/home/user/.minetest/world"
|
||||
^ Useful for storing custom data
|
||||
|
||||
minetest.register_entity(name, prototype table)
|
||||
minetest.register_abm(abm definition)
|
||||
minetest.register_node(name, node definition)
|
||||
@ -372,6 +404,7 @@ minetest.register_tool(name, item definition)
|
||||
minetest.register_craftitem(name, item definition)
|
||||
minetest.register_alias(name, convert_to)
|
||||
minetest.register_craft(recipe)
|
||||
|
||||
minetest.register_globalstep(func(dtime))
|
||||
minetest.register_on_placenode(func(pos, newnode, placer))
|
||||
minetest.register_on_dignode(func(pos, oldnode, digger))
|
||||
@ -383,20 +416,22 @@ minetest.register_on_respawnplayer(func(ObjectRef))
|
||||
^ return true in func to disable regular player placement
|
||||
^ currently called _before_ repositioning of player occurs
|
||||
minetest.register_on_chat_message(func(name, message))
|
||||
|
||||
minetest.add_to_creative_inventory(itemstring)
|
||||
minetest.setting_get(name) -> string or nil
|
||||
minetest.setting_getbool(name) -> boolean value or nil
|
||||
|
||||
minetest.chat_send_all(text)
|
||||
minetest.chat_send_player(name, text)
|
||||
minetest.get_player_privs(name) -> set of privs
|
||||
minetest.get_inventory(location) -> InvRef
|
||||
^ location = eg. {type="player", name="celeron55"}
|
||||
{type="node", pos={x=, y=, z=}}
|
||||
minetest.get_current_modname() -> string
|
||||
minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname"
|
||||
^ Useful for loading additional .lua modules or static data from mod
|
||||
minetest.get_worldpath(modname) -> eg. "/home/user/.minetest/world"
|
||||
^ Useful for storing custom data
|
||||
|
||||
minetest.sound_play(spec, parameters) -> handle
|
||||
^ spec = SimpleSoundSpec
|
||||
^ parameters = sound parameter table
|
||||
minetest.sound_stop(handle)
|
||||
|
||||
minetest.debug(line)
|
||||
^ Goes to dstream
|
||||
@ -681,6 +716,7 @@ Node definition (register_node)
|
||||
legacy_wallmounted = false, -- Support maps made in and before January 2012
|
||||
sounds = {
|
||||
footstep = <SimpleSoundSpec>,
|
||||
dig = <SimpleSoundSpec>, -- "__group" = group-based sound (default)
|
||||
dug = <SimpleSoundSpec>,
|
||||
},
|
||||
}
|
||||
|
@ -6,6 +6,42 @@
|
||||
|
||||
experimental = {}
|
||||
|
||||
timers_to_add = {}
|
||||
timers = {}
|
||||
minetest.register_globalstep(function(dtime)
|
||||
for indes, timer in ipairs(timers_to_add) do
|
||||
table.insert(timers, timer)
|
||||
end
|
||||
timers_to_add = {}
|
||||
for index, timer in ipairs(timers) do
|
||||
timer.time = timer.time - dtime
|
||||
if timer.time <= 0 then
|
||||
timer.func()
|
||||
timers[index] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
after = function(time, func)
|
||||
table.insert(timers_to_add, {time=time, func=func})
|
||||
end
|
||||
|
||||
--[[
|
||||
stepsound = -1
|
||||
function test_sound()
|
||||
print("test_sound")
|
||||
stepsound = minetest.sound_play("default_grass_footstep", {gain=1.0})
|
||||
after(2.0, test_sound)
|
||||
--after(0.1, test_sound_stop)
|
||||
end
|
||||
function test_sound_stop()
|
||||
print("test_sound_stop")
|
||||
minetest.sound_stop(stepsound)
|
||||
after(2.0, test_sound)
|
||||
end
|
||||
test_sound()
|
||||
--]]
|
||||
|
||||
function on_step(dtime)
|
||||
-- print("experimental on_step")
|
||||
--[[
|
||||
|
111
src/client.cpp
111
src/client.cpp
@ -261,7 +261,8 @@ Client::Client(
|
||||
m_nodedef_received(false),
|
||||
m_time_of_day_set(false),
|
||||
m_last_time_of_day_f(-1),
|
||||
m_time_of_day_update_timer(0)
|
||||
m_time_of_day_update_timer(0),
|
||||
m_removed_sounds_check_timer(0)
|
||||
{
|
||||
m_packetcounter_timer = 0.0;
|
||||
//m_delete_unused_sectors_timer = 0.0;
|
||||
@ -733,6 +734,63 @@ void Client::step(float dtime)
|
||||
m_inventory_updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Update positions of sounds attached to objects
|
||||
*/
|
||||
{
|
||||
for(std::map<int, u16>::iterator
|
||||
i = m_sounds_to_objects.begin();
|
||||
i != m_sounds_to_objects.end(); i++)
|
||||
{
|
||||
int client_id = i->first;
|
||||
u16 object_id = i->second;
|
||||
ClientActiveObject *cao = m_env.getActiveObject(object_id);
|
||||
if(!cao)
|
||||
continue;
|
||||
v3f pos = cao->getPosition();
|
||||
m_sound->updateSoundPosition(client_id, pos);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Handle removed remotely initiated sounds
|
||||
*/
|
||||
m_removed_sounds_check_timer += dtime;
|
||||
if(m_removed_sounds_check_timer >= 2.32)
|
||||
{
|
||||
m_removed_sounds_check_timer = 0;
|
||||
// Find removed sounds and clear references to them
|
||||
std::set<s32> removed_server_ids;
|
||||
for(std::map<s32, int>::iterator
|
||||
i = m_sounds_server_to_client.begin();
|
||||
i != m_sounds_server_to_client.end();)
|
||||
{
|
||||
s32 server_id = i->first;
|
||||
int client_id = i->second;
|
||||
i++;
|
||||
if(!m_sound->soundExists(client_id)){
|
||||
m_sounds_server_to_client.erase(server_id);
|
||||
m_sounds_client_to_server.erase(client_id);
|
||||
m_sounds_to_objects.erase(client_id);
|
||||
removed_server_ids.insert(server_id);
|
||||
}
|
||||
}
|
||||
// Sync to server
|
||||
if(removed_server_ids.size() != 0)
|
||||
{
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
writeU16(os, TOSERVER_REMOVED_SOUNDS);
|
||||
writeU16(os, removed_server_ids.size());
|
||||
for(std::set<s32>::iterator i = removed_server_ids.begin();
|
||||
i != removed_server_ids.end(); i++)
|
||||
writeS32(os, *i);
|
||||
std::string s = os.str();
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send as reliable
|
||||
Send(0, data, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Virtual methods from con::PeerHandler
|
||||
@ -1610,6 +1668,57 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
m_itemdef->deSerialize(tmp_is2);
|
||||
m_itemdef_received = true;
|
||||
}
|
||||
else if(command == TOCLIENT_PLAY_SOUND)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
s32 server_id = readS32(is);
|
||||
std::string name = deSerializeString(is);
|
||||
float gain = readF1000(is);
|
||||
int type = readU8(is); // 0=local, 1=positional, 2=object
|
||||
v3f pos = readV3F1000(is);
|
||||
u16 object_id = readU16(is);
|
||||
bool loop = readU8(is);
|
||||
// Start playing
|
||||
int client_id = -1;
|
||||
switch(type){
|
||||
case 0: // local
|
||||
client_id = m_sound->playSound(name, false, gain);
|
||||
break;
|
||||
case 1: // positional
|
||||
client_id = m_sound->playSoundAt(name, false, gain, pos);
|
||||
break;
|
||||
case 2: { // object
|
||||
ClientActiveObject *cao = m_env.getActiveObject(object_id);
|
||||
if(cao)
|
||||
pos = cao->getPosition();
|
||||
client_id = m_sound->playSoundAt(name, loop, gain, pos);
|
||||
// TODO: Set up sound to move with object
|
||||
break; }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(client_id != -1){
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if(command == TOCLIENT_STOP_SOUND)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
s32 server_id = readS32(is);
|
||||
std::map<s32, int>::iterator i =
|
||||
m_sounds_server_to_client.find(server_id);
|
||||
if(i != m_sounds_server_to_client.end()){
|
||||
int client_id = i->second;
|
||||
m_sound->stopSound(client_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Client: Ignoring unknown command "
|
||||
|
@ -376,6 +376,15 @@ private:
|
||||
bool m_time_of_day_set;
|
||||
float m_last_time_of_day_f;
|
||||
float m_time_of_day_update_timer;
|
||||
|
||||
// Sounds
|
||||
float m_removed_sounds_check_timer;
|
||||
// Mapping from server sound ids to our sound ids
|
||||
std::map<s32, int> m_sounds_server_to_client;
|
||||
// And the other way!
|
||||
std::map<int, s32> m_sounds_client_to_server;
|
||||
// And relations to objects
|
||||
std::map<int, u16> m_sounds_to_objects;
|
||||
};
|
||||
|
||||
#endif // !SERVER
|
||||
|
@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
Compress the contents of TOCLIENT_ITEMDEF and TOCLIENT_NODEDEF
|
||||
PROTOCOL_VERSION 8:
|
||||
Digging based on item groups
|
||||
Many things
|
||||
*/
|
||||
|
||||
#define PROTOCOL_VERSION 8
|
||||
@ -268,7 +269,25 @@ enum ToClientCommand
|
||||
u32 length of next item
|
||||
serialized ItemDefManager
|
||||
*/
|
||||
|
||||
TOCLIENT_PLAY_SOUND = 0x3f,
|
||||
/*
|
||||
u16 command
|
||||
s32 sound_id
|
||||
u16 len
|
||||
u8[len] sound name
|
||||
s32 gain*1000
|
||||
u8 type (0=local, 1=positional, 2=object)
|
||||
s32[3] pos_nodes*10000
|
||||
u16 object_id
|
||||
u8 loop (bool)
|
||||
*/
|
||||
|
||||
TOCLIENT_STOP_SOUND = 0x40,
|
||||
/*
|
||||
u16 command
|
||||
s32 sound_id
|
||||
*/
|
||||
};
|
||||
|
||||
enum ToServerCommand
|
||||
@ -442,15 +461,21 @@ enum ToServerCommand
|
||||
(Obsoletes TOSERVER_GROUND_ACTION and TOSERVER_CLICK_ACTIVEOBJECT.)
|
||||
*/
|
||||
|
||||
TOSERVER_REQUEST_TEXTURES = 0x40,
|
||||
|
||||
TOSERVER_REMOVED_SOUNDS = 0x3a,
|
||||
/*
|
||||
u16 command
|
||||
u16 number of textures requested
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
}
|
||||
u16 command
|
||||
u16 len
|
||||
s32[len] sound_id
|
||||
*/
|
||||
|
||||
TOSERVER_REQUEST_TEXTURES = 0x40,
|
||||
/*
|
||||
u16 command
|
||||
u16 number of textures requested
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
}
|
||||
*/
|
||||
|
||||
};
|
||||
|
@ -34,6 +34,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "itemdef.h"
|
||||
#include "tool.h"
|
||||
#include "content_cso.h"
|
||||
#include "sound.h"
|
||||
#include "nodedef.h"
|
||||
class Settings;
|
||||
struct ToolCapabilities;
|
||||
|
||||
@ -1008,6 +1010,7 @@ private:
|
||||
LocalPlayer *m_local_player;
|
||||
float m_damage_visual_timer;
|
||||
bool m_dead;
|
||||
float m_step_distance_counter;
|
||||
|
||||
public:
|
||||
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
|
||||
@ -1020,7 +1023,8 @@ public:
|
||||
m_is_local_player(false),
|
||||
m_local_player(NULL),
|
||||
m_damage_visual_timer(0),
|
||||
m_dead(false)
|
||||
m_dead(false),
|
||||
m_step_distance_counter(0)
|
||||
{
|
||||
if(gamedef == NULL)
|
||||
ClientActiveObject::registerType(getType(), create);
|
||||
@ -1202,7 +1206,9 @@ public:
|
||||
|
||||
void step(float dtime, ClientEnvironment *env)
|
||||
{
|
||||
v3f lastpos = pos_translator.vect_show;
|
||||
pos_translator.translate(dtime);
|
||||
float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
|
||||
updateVisibility();
|
||||
updateNodePos();
|
||||
|
||||
@ -1212,6 +1218,18 @@ public:
|
||||
updateTextures("");
|
||||
}
|
||||
}
|
||||
|
||||
m_step_distance_counter += moved;
|
||||
if(m_step_distance_counter > 1.5*BS){
|
||||
m_step_distance_counter = 0;
|
||||
if(!m_is_local_player){
|
||||
INodeDefManager *ndef = m_gamedef->ndef();
|
||||
v3s16 p = floatToInt(getPosition()+v3f(0,-0.5*BS, 0), BS);
|
||||
MapNode n = m_env->getMap().getNodeNoEx(p);
|
||||
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
|
||||
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processMessage(const std::string &data)
|
||||
|
@ -2222,7 +2222,7 @@ private:
|
||||
|
||||
static const char className[];
|
||||
static const luaL_reg methods[];
|
||||
|
||||
public:
|
||||
static ObjectRef *checkobject(lua_State *L, int narg)
|
||||
{
|
||||
luaL_checktype(L, narg, LUA_TUSERDATA);
|
||||
@ -2236,7 +2236,7 @@ private:
|
||||
ServerActiveObject *co = ref->m_object;
|
||||
return co;
|
||||
}
|
||||
|
||||
private:
|
||||
static LuaEntitySAO* getluaobject(ObjectRef *ref)
|
||||
{
|
||||
ServerActiveObject *obj = getobject(ref);
|
||||
@ -3134,10 +3134,6 @@ const luaL_reg EnvRef::methods[] = {
|
||||
{0,0}
|
||||
};
|
||||
|
||||
/*
|
||||
Global functions
|
||||
*/
|
||||
|
||||
class LuaABM : public ActiveBlockModifier
|
||||
{
|
||||
private:
|
||||
@ -3211,6 +3207,47 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
ServerSoundParams
|
||||
*/
|
||||
|
||||
static void read_server_sound_params(lua_State *L, int index,
|
||||
ServerSoundParams ¶ms)
|
||||
{
|
||||
if(index < 0)
|
||||
index = lua_gettop(L) + 1 + index;
|
||||
// Clear
|
||||
params = ServerSoundParams();
|
||||
if(lua_istable(L, index)){
|
||||
getfloatfield(L, index, "gain", params.gain);
|
||||
getstringfield(L, index, "to_player", params.to_player);
|
||||
lua_getfield(L, index, "pos");
|
||||
if(!lua_isnil(L, -1)){
|
||||
v3f p = read_v3f(L, -1)*BS;
|
||||
params.pos = p;
|
||||
params.type = ServerSoundParams::SSP_POSITIONAL;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, index, "object");
|
||||
if(!lua_isnil(L, -1)){
|
||||
ObjectRef *ref = ObjectRef::checkobject(L, -1);
|
||||
ServerActiveObject *sao = ObjectRef::getobject(ref);
|
||||
if(sao){
|
||||
params.object = sao->getId();
|
||||
params.type = ServerSoundParams::SSP_OBJECT;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
params.max_hear_distance = BS*getfloatfield_default(L, index,
|
||||
"max_hear_distance", params.max_hear_distance/BS);
|
||||
getboolfield(L, index, "loop", params.loop);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Global functions
|
||||
*/
|
||||
|
||||
// debug(text)
|
||||
// Writes a line to dstream
|
||||
static int l_debug(lua_State *L)
|
||||
@ -3674,6 +3711,26 @@ static int l_get_worldpath(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// sound_play(spec, parameters)
|
||||
static int l_sound_play(lua_State *L)
|
||||
{
|
||||
SimpleSoundSpec spec;
|
||||
read_soundspec(L, 1, spec);
|
||||
ServerSoundParams params;
|
||||
read_server_sound_params(L, 2, params);
|
||||
s32 handle = get_server(L)->playSound(spec, params);
|
||||
lua_pushinteger(L, handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// sound_stop(handle)
|
||||
static int l_sound_stop(lua_State *L)
|
||||
{
|
||||
int handle = luaL_checkinteger(L, 1);
|
||||
get_server(L)->stopSound(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct luaL_Reg minetest_f [] = {
|
||||
{"debug", l_debug},
|
||||
{"log", l_log},
|
||||
@ -3691,6 +3748,8 @@ static const struct luaL_Reg minetest_f [] = {
|
||||
{"get_current_modname", l_get_current_modname},
|
||||
{"get_modpath", l_get_modpath},
|
||||
{"get_worldpath", l_get_worldpath},
|
||||
{"sound_play", l_sound_play},
|
||||
{"sound_stop", l_sound_stop},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
134
src/server.cpp
134
src/server.cpp
@ -3126,6 +3126,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
<<action<<std::endl;
|
||||
}
|
||||
}
|
||||
else if(command == TOSERVER_REMOVED_SOUNDS)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
int num = readU16(is);
|
||||
for(int k=0; k<num; k++){
|
||||
s32 id = readS32(is);
|
||||
std::map<s32, ServerPlayingSound>::iterator i =
|
||||
m_playing_sounds.find(id);
|
||||
if(i == m_playing_sounds.end())
|
||||
continue;
|
||||
ServerPlayingSound &psound = i->second;
|
||||
psound.clients.erase(peer_id);
|
||||
if(psound.clients.size() == 0)
|
||||
m_playing_sounds.erase(i++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Server::ProcessData(): Ignoring "
|
||||
@ -3575,6 +3593,107 @@ void Server::SendMovePlayer(Player *player)
|
||||
m_con.Send(player->peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
s32 Server::playSound(const SimpleSoundSpec &spec,
|
||||
const ServerSoundParams ¶ms)
|
||||
{
|
||||
// Find out initial position of sound
|
||||
bool pos_exists = false;
|
||||
v3f pos = params.getPos(m_env, &pos_exists);
|
||||
// If position is not found while it should be, cancel sound
|
||||
if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
|
||||
return -1;
|
||||
// Filter destination clients
|
||||
std::set<RemoteClient*> dst_clients;
|
||||
if(params.to_player != "")
|
||||
{
|
||||
Player *player = m_env->getPlayer(params.to_player.c_str());
|
||||
if(!player){
|
||||
infostream<<"Server::playSound: Player \""<<params.to_player
|
||||
<<"\" not found"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
if(player->peer_id == PEER_ID_INEXISTENT){
|
||||
infostream<<"Server::playSound: Player \""<<params.to_player
|
||||
<<"\" not connected"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
RemoteClient *client = getClient(player->peer_id);
|
||||
dst_clients.insert(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(core::map<u16, RemoteClient*>::Iterator
|
||||
i = m_clients.getIterator(); i.atEnd() == false; i++)
|
||||
{
|
||||
RemoteClient *client = i.getNode()->getValue();
|
||||
Player *player = m_env->getPlayer(client->peer_id);
|
||||
if(!player)
|
||||
continue;
|
||||
if(pos_exists){
|
||||
if(player->getPosition().getDistanceFrom(pos) >
|
||||
params.max_hear_distance)
|
||||
continue;
|
||||
}
|
||||
dst_clients.insert(client);
|
||||
}
|
||||
}
|
||||
if(dst_clients.size() == 0)
|
||||
return -1;
|
||||
// Create the sound
|
||||
s32 id = m_next_sound_id++;
|
||||
// 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;
|
||||
for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
|
||||
i != dst_clients.end(); i++)
|
||||
psound.clients.insert((*i)->peer_id);
|
||||
// Create packet
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
writeU16(os, TOCLIENT_PLAY_SOUND);
|
||||
writeS32(os, id);
|
||||
os<<serializeString(spec.name);
|
||||
writeF1000(os, spec.gain * params.gain);
|
||||
writeU8(os, params.type);
|
||||
writeV3F1000(os, pos);
|
||||
writeU16(os, params.object);
|
||||
writeU8(os, params.loop);
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send
|
||||
for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
|
||||
i != dst_clients.end(); i++){
|
||||
// Send as reliable
|
||||
m_con.Send((*i)->peer_id, 0, data, true);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
void Server::stopSound(s32 handle)
|
||||
{
|
||||
// Get sound reference
|
||||
std::map<s32, ServerPlayingSound>::iterator i =
|
||||
m_playing_sounds.find(handle);
|
||||
if(i == m_playing_sounds.end())
|
||||
return;
|
||||
ServerPlayingSound &psound = i->second;
|
||||
// Create packet
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
writeU16(os, TOCLIENT_STOP_SOUND);
|
||||
writeS32(os, handle);
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send
|
||||
for(std::set<u16>::iterator i = psound.clients.begin();
|
||||
i != psound.clients.end(); i++){
|
||||
// Send as reliable
|
||||
m_con.Send(*i, 0, data, true);
|
||||
}
|
||||
// Remove sound reference
|
||||
m_playing_sounds.erase(i);
|
||||
}
|
||||
|
||||
void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
|
||||
core::list<u16> *far_players, float far_d_nodes)
|
||||
{
|
||||
@ -4511,6 +4630,21 @@ void Server::handlePeerChange(PeerChange &c)
|
||||
obj->m_known_by_count--;
|
||||
}
|
||||
|
||||
/*
|
||||
Clear references to playing sounds
|
||||
*/
|
||||
for(std::map<s32, ServerPlayingSound>::iterator
|
||||
i = m_playing_sounds.begin();
|
||||
i != m_playing_sounds.end();)
|
||||
{
|
||||
ServerPlayingSound &psound = i->second;
|
||||
psound.clients.erase(c.peer_id);
|
||||
if(psound.clients.size() == 0)
|
||||
m_playing_sounds.erase(i++);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
|
||||
ServerRemotePlayer* player =
|
||||
static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
|
||||
|
||||
|
64
src/server.h
64
src/server.h
@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mods.h"
|
||||
#include "inventorymanager.h"
|
||||
#include "subgame.h"
|
||||
#include "sound.h"
|
||||
struct LuaState;
|
||||
typedef struct lua_State lua_State;
|
||||
class IWritableItemDefManager;
|
||||
@ -274,6 +275,58 @@ struct TextureInformation
|
||||
}
|
||||
};
|
||||
|
||||
struct ServerSoundParams
|
||||
{
|
||||
float gain;
|
||||
std::string to_player;
|
||||
enum Type{
|
||||
SSP_LOCAL=0,
|
||||
SSP_POSITIONAL=1,
|
||||
SSP_OBJECT=2
|
||||
} type;
|
||||
v3f pos;
|
||||
u16 object;
|
||||
float max_hear_distance;
|
||||
bool loop;
|
||||
|
||||
ServerSoundParams():
|
||||
gain(1.0),
|
||||
to_player(""),
|
||||
type(SSP_LOCAL),
|
||||
pos(0,0,0),
|
||||
object(0),
|
||||
max_hear_distance(32*BS),
|
||||
loop(false)
|
||||
{}
|
||||
|
||||
v3f getPos(ServerEnvironment *env, bool *pos_exists) const
|
||||
{
|
||||
if(pos_exists) *pos_exists = false;
|
||||
switch(type){
|
||||
case SSP_LOCAL:
|
||||
return v3f(0,0,0);
|
||||
case SSP_POSITIONAL:
|
||||
if(pos_exists) *pos_exists = true;
|
||||
return pos;
|
||||
case SSP_OBJECT: {
|
||||
if(object == 0)
|
||||
return v3f(0,0,0);
|
||||
ServerActiveObject *sao = env->getActiveObject(object);
|
||||
if(!sao)
|
||||
return v3f(0,0,0);
|
||||
if(pos_exists) *pos_exists = true;
|
||||
return sao->getBasePosition(); }
|
||||
}
|
||||
return v3f(0,0,0);
|
||||
}
|
||||
};
|
||||
|
||||
struct ServerPlayingSound
|
||||
{
|
||||
ServerSoundParams params;
|
||||
std::set<u16> clients; // peer ids
|
||||
};
|
||||
|
||||
class RemoteClient
|
||||
{
|
||||
public:
|
||||
@ -464,6 +517,11 @@ public:
|
||||
// Envlock and conlock should be locked when calling this
|
||||
void SendMovePlayer(Player *player);
|
||||
|
||||
// Returns -1 if failed, sound handle on success
|
||||
// Envlock + conlock
|
||||
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
|
||||
void stopSound(s32 handle);
|
||||
|
||||
// Thread-safe
|
||||
u64 getPlayerAuthPrivs(const std::string &name);
|
||||
void setPlayerAuthPrivs(const std::string &name, u64 privs);
|
||||
@ -775,6 +833,12 @@ private:
|
||||
friend class RemoteClient;
|
||||
|
||||
std::map<std::string,TextureInformation> m_Textures;
|
||||
|
||||
/*
|
||||
Sounds
|
||||
*/
|
||||
std::map<s32, ServerPlayingSound> m_playing_sounds;
|
||||
s32 m_next_sound_id;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -67,6 +67,8 @@ public:
|
||||
virtual int playSoundAt(const std::string &name, bool loop,
|
||||
float volume, v3f pos) = 0;
|
||||
virtual void stopSound(int sound) = 0;
|
||||
virtual bool soundExists(int sound) = 0;
|
||||
virtual void updateSoundPosition(int sound, v3f pos) = 0;
|
||||
|
||||
int playSound(const SimpleSoundSpec &spec, bool loop)
|
||||
{ return playSound(spec.name, loop, spec.gain); }
|
||||
@ -87,6 +89,8 @@ public:
|
||||
int playSoundAt(const std::string &name, bool loop,
|
||||
float volume, v3f pos) {return 0;}
|
||||
void stopSound(int sound) {}
|
||||
bool soundExists(int sound) {return false;}
|
||||
void updateSoundPosition(int sound, v3f pos) {}
|
||||
};
|
||||
|
||||
// Global DummySoundManager singleton
|
||||
|
@ -482,6 +482,24 @@ public:
|
||||
maintain();
|
||||
deleteSound(sound);
|
||||
}
|
||||
bool soundExists(int sound)
|
||||
{
|
||||
maintain();
|
||||
return (m_sounds_playing.count(sound) != 0);
|
||||
}
|
||||
void updateSoundPosition(int id, v3f pos)
|
||||
{
|
||||
std::map<int, PlayingSound*>::iterator i =
|
||||
m_sounds_playing.find(id);
|
||||
if(i == m_sounds_playing.end())
|
||||
return;
|
||||
PlayingSound *sound = i->second;
|
||||
|
||||
alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
|
||||
alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
|
||||
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
|
||||
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
|
||||
}
|
||||
};
|
||||
|
||||
ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
|
||||
|
Loading…
Reference in New Issue
Block a user