17 changes: 9 additions & 8 deletions src/nodedef.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ class Client;
#include "texture_override.h" // TextureOverride
#include "tileanimation.h"

// PROTOCOL_VERSION >= 37
static const u8 CONTENTFEATURES_VERSION = 13;

class IItemDefManager;
class ITextureSource;
class IShaderSource;
Expand Down Expand Up @@ -286,8 +283,7 @@ struct TileDef
}

void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is, u8 contentfeatures_version,
NodeDrawType drawtype);
void deSerialize(std::istream &is, NodeDrawType drawtype, u16 protocol_version);
};

// Defines the number of special tiles per nodedef
Expand All @@ -299,6 +295,10 @@ struct TileDef

struct ContentFeatures
{
// PROTOCOL_VERSION >= 37. This is legacy and should not be increased anymore,
// write checks that depend directly on the protocol version instead.
static const u8 CONTENTFEATURES_VERSION = 13;

/*
Cached stuff
*/
Expand Down Expand Up @@ -447,7 +447,7 @@ struct ContentFeatures
~ContentFeatures();
void reset();
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
void deSerialize(std::istream &is, u16 protocol_version);

/*
Some handy methods
Expand Down Expand Up @@ -690,16 +690,17 @@ class NodeDefManager {

/*!
* Writes the content of this manager to the given output stream.
* @param protocol_version serialization version of ContentFeatures
* @param protocol_version Active network protocol version
*/
void serialize(std::ostream &os, u16 protocol_version) const;

/*!
* Restores the manager from a serialized stream.
* This clears the previous state.
* @param is input stream containing a serialized NodeDefManager
* @param protocol_version Active network protocol version
*/
void deSerialize(std::istream &is);
void deSerialize(std::istream &is, u16 protocol_version);

/*!
* Used to indicate that node registration has finished.
Expand Down
19 changes: 11 additions & 8 deletions src/script/common/c_content.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,22 +1051,26 @@ void push_palette(lua_State *L, const std::vector<video::SColor> *palette)

/******************************************************************************/
void read_server_sound_params(lua_State *L, int index,
ServerSoundParams &params)
ServerPlayingSound &params)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
// Clear
params = ServerSoundParams();

if(lua_istable(L, index)){
// Functional overlap: this may modify SimpleSoundSpec contents
getfloatfield(L, index, "fade", params.spec.fade);
getfloatfield(L, index, "pitch", params.spec.pitch);
getboolfield(L, index, "loop", params.spec.loop);

getfloatfield(L, index, "gain", params.gain);

// Handle positional information
getstringfield(L, index, "to_player", params.to_player);
getfloatfield(L, index, "fade", params.fade);
getfloatfield(L, index, "pitch", params.pitch);
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;
params.type = ServerPlayingSound::SSP_POSITIONAL;
}
lua_pop(L, 1);
lua_getfield(L, index, "object");
Expand All @@ -1075,13 +1079,12 @@ void read_server_sound_params(lua_State *L, int index,
ServerActiveObject *sao = ObjectRef::getobject(ref);
if(sao){
params.object = sao->getId();
params.type = ServerSoundParams::SSP_OBJECT;
params.type = ServerPlayingSound::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);
getstringfield(L, index, "exclude_player", params.exclude_player);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/script/common/c_content.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct ItemDefinition;
struct ToolCapabilities;
struct ObjectProperties;
struct SimpleSoundSpec;
struct ServerSoundParams;
struct ServerPlayingSound;
class Inventory;
class InventoryList;
struct NodeBox;
Expand Down Expand Up @@ -91,7 +91,7 @@ void read_soundspec (lua_State *L, int index,
NodeBox read_nodebox (lua_State *L, int index);

void read_server_sound_params (lua_State *L, int index,
ServerSoundParams &params);
ServerPlayingSound &params);

void push_dig_params (lua_State *L,
const DigParams &params);
Expand Down
9 changes: 4 additions & 5 deletions src/script/lua_api/l_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,16 +437,15 @@ int ModApiServer::l_get_worldpath(lua_State *L)
int ModApiServer::l_sound_play(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
SimpleSoundSpec spec;
read_soundspec(L, 1, spec);
ServerSoundParams params;
ServerPlayingSound params;
read_soundspec(L, 1, params.spec);
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);
getServer(L)->playSound(params, true);
lua_pushnil(L);
} else {
s32 handle = getServer(L)->playSound(spec, params);
s32 handle = getServer(L)->playSound(params);
lua_pushinteger(L, handle);
}
return 1;
Expand Down
4 changes: 2 additions & 2 deletions src/script/lua_api/l_sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ int ModApiSound::l_sound_play(lua_State *L)
{
SimpleSoundSpec spec;
read_soundspec(L, 1, spec);
bool looped = readParam<bool>(L, 2);
spec.loop = readParam<bool>(L, 2);

s32 handle = getGuiEngine(L)->playSound(spec, looped);
s32 handle = getGuiEngine(L)->playSound(spec);

lua_pushinteger(L, handle);

Expand Down
98 changes: 32 additions & 66 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void *ServerThread::run()
return nullptr;
}

v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
v3f ServerPlayingSound::getPos(ServerEnvironment *env, bool *pos_exists) const
{
if(pos_exists) *pos_exists = false;
switch(type){
Expand Down Expand Up @@ -2066,14 +2066,13 @@ inline s32 Server::nextSoundId()
return ret;
}

s32 Server::playSound(const SimpleSoundSpec &spec,
const ServerSoundParams &params, bool ephemeral)
s32 Server::playSound(ServerPlayingSound &params, bool ephemeral)
{
// 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))
if(pos_exists != (params.type != ServerPlayingSound::SSP_LOCAL))
return -1;

// Filter destination clients
Expand Down Expand Up @@ -2118,101 +2117,68 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
if(dst_clients.empty())
return -1;

// Create the sound
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();
psound = &m_playing_sounds[id];
psound->params = params;
psound->spec = spec;
}
// old clients will still use this, so pick a reserved ID (-1)
const s32 id = ephemeral ? -1 : nextSoundId();

float gain = params.gain * spec.gain;
float gain = params.gain * params.spec.gain;
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
pkt << id << spec.name << gain
pkt << id << params.spec.name << gain
<< (u8) params.type << pos << params.object
<< params.loop << params.fade << params.pitch
<< params.spec.loop << params.spec.fade << params.spec.pitch
<< ephemeral;

bool as_reliable = !ephemeral;

for (const u16 dst_client : dst_clients) {
if (psound)
psound->clients.insert(dst_client);
m_clients.send(dst_client, 0, &pkt, as_reliable);
for (const session_t peer_id : dst_clients) {
if (!ephemeral)
params.clients.insert(peer_id);
m_clients.send(peer_id, 0, &pkt, as_reliable);
}

if (!ephemeral)
m_playing_sounds[id] = std::move(params);
return id;
}
void Server::stopSound(s32 handle)
{
// Get sound reference
std::unordered_map<s32, ServerPlayingSound>::iterator i =
m_playing_sounds.find(handle);
if (i == m_playing_sounds.end())
auto it = m_playing_sounds.find(handle);
if (it == m_playing_sounds.end())
return;
ServerPlayingSound &psound = i->second;

ServerPlayingSound &psound = it->second;

NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
pkt << handle;

for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
si != psound.clients.end(); ++si) {
for (session_t peer_id : psound.clients) {
// Send as reliable
m_clients.send(*si, 0, &pkt, true);
m_clients.send(peer_id, 0, &pkt, true);
}

// Remove sound reference
m_playing_sounds.erase(i);
m_playing_sounds.erase(it);
}

void Server::fadeSound(s32 handle, float step, float gain)
{
// Get sound reference
std::unordered_map<s32, ServerPlayingSound>::iterator i =
m_playing_sounds.find(handle);
if (i == m_playing_sounds.end())
auto it = m_playing_sounds.find(handle);
if (it == m_playing_sounds.end())
return;

ServerPlayingSound &psound = i->second;
psound.params.gain = gain;
ServerPlayingSound &psound = it->second;
psound.gain = gain; // destination gain

NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
pkt << handle << step << gain;

// Backwards compability
bool play_sound = gain > 0;
ServerPlayingSound compat_psound = psound;
compat_psound.clients.clear();

NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
compat_pkt << handle;

for (std::unordered_set<u16>::iterator it = psound.clients.begin();
it != psound.clients.end();) {
if (m_clients.getProtocolVersion(*it) >= 32) {
// Send as reliable
m_clients.send(*it, 0, &pkt, true);
++it;
} else {
compat_psound.clients.insert(*it);
// Stop old sound
m_clients.send(*it, 0, &compat_pkt, true);
psound.clients.erase(it++);
}
for (session_t peer_id : psound.clients) {
// Send as reliable
m_clients.send(peer_id, 0, &pkt, true);
}

// Remove sound reference
if (!play_sound || psound.clients.empty())
m_playing_sounds.erase(i);

if (play_sound && !compat_psound.clients.empty()) {
// Play new sound volume on older clients
playSound(compat_psound.spec, compat_psound.params);
}
if (gain <= 0 || psound.clients.empty())
m_playing_sounds.erase(it);
}

void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
Expand Down
21 changes: 8 additions & 13 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,30 +96,26 @@ struct MediaInfo
}
};

struct ServerSoundParams
// Combines the pure sound (SimpleSoundSpec) with positional information
struct ServerPlayingSound
{
enum Type {
SSP_LOCAL,
SSP_POSITIONAL,
SSP_OBJECT
} type = SSP_LOCAL;
float gain = 1.0f;
float fade = 0.0f;
float pitch = 1.0f;
bool loop = false;

float gain = 1.0f; // for amplification of the base sound
float max_hear_distance = 32 * BS;
v3f pos;
u16 object = 0;
std::string to_player = "";
std::string exclude_player = "";
std::string to_player;
std::string exclude_player;

v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
};

struct ServerPlayingSound
{
ServerSoundParams params;
SimpleSoundSpec spec;

std::unordered_set<session_t> clients; // peer ids
};

Expand Down Expand Up @@ -236,8 +232,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,

// Returns -1 if failed, sound handle on success
// Envlock
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params,
bool ephemeral=false);
s32 playSound(ServerPlayingSound &params, bool ephemeral=false);
void stopSound(s32 handle);
void fadeSound(s32 handle, float step, float gain);

Expand Down
17 changes: 8 additions & 9 deletions src/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h"
#include "irrlichttypes_bloated.h"

// This class describes the basic sound information for playback.
// Positional handling is done separately.

struct SimpleSoundSpec
{
SimpleSoundSpec(const std::string &name = "", float gain = 1.0f,
float fade = 0.0f, float pitch = 1.0f) :
name(name),
gain(gain), fade(fade), pitch(pitch)
bool loop = false, float fade = 0.0f, float pitch = 1.0f) :
name(name), gain(gain), fade(fade), pitch(pitch), loop(loop)
{
}

bool exists() const { return !name.empty(); }

// Take cf_version from ContentFeatures::serialize to
// keep in sync with item definitions
void serialize(std::ostream &os, u8 cf_version) const
void serialize(std::ostream &os, u16 protocol_version) const
{
os << serializeString16(name);
writeF32(os, gain);
writeF32(os, pitch);
writeF32(os, fade);
// if (cf_version < ?)
// return;
}

void deSerialize(std::istream &is, u8 cf_version)
void deSerialize(std::istream &is, u16 protocol_version)
{
name = deSerializeString16(is);
gain = readF32(is);
Expand All @@ -59,4 +57,5 @@ struct SimpleSoundSpec
float gain = 1.0f;
float fade = 0.0f;
float pitch = 1.0f;
bool loop = false;
};
4 changes: 2 additions & 2 deletions src/tileanimation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tileanimation.h"
#include "util/serialize.h"

void TileAnimationParams::serialize(std::ostream &os, u8 tiledef_version) const
void TileAnimationParams::serialize(std::ostream &os, u16 protocol_version) const
{
writeU8(os, type);
if (type == TAT_VERTICAL_FRAMES) {
Expand All @@ -33,7 +33,7 @@ void TileAnimationParams::serialize(std::ostream &os, u8 tiledef_version) const
}
}

void TileAnimationParams::deSerialize(std::istream &is, u8 tiledef_version)
void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version)
{
type = (TileAnimationType) readU8(is);

Expand Down
4 changes: 2 additions & 2 deletions src/tileanimation.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ struct TileAnimationParams
} sheet_2d;
};

void serialize(std::ostream &os, u8 tiledef_version) const;
void deSerialize(std::istream &is, u8 tiledef_version);
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is, u16 protocol_version);
void determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms,
v2u32 *frame_size) const;
void getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const;
Expand Down
2 changes: 1 addition & 1 deletion src/unittest/test_nodedef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void TestNodeDef::testContentFeaturesSerialization()

std::istringstream is(os.str(), std::ios::binary);
ContentFeatures f2;
f2.deSerialize(is);
f2.deSerialize(is, LATEST_PROTOCOL_VERSION);

UASSERT(f.walkable == f2.walkable);
UASSERT(f.node_box.type == f2.node_box.type);
Expand Down