X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fserver.cpp;h=b3992b9b15197f69c915ecdbe59888d467f4203f;hb=7c43cf47c37b0204e34d12670d2e6975eb36b45a;hp=f6bf491becbdf5bffe31f31ddf75315bc6f7b613;hpb=fae6242d4ef6ca34d131054484acf5efc2fcba70;p=oweals%2Fminetest.git diff --git a/src/server.cpp b/src/server.cpp index f6bf491be..b3992b9b1 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -34,8 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "filesys.h" #include "mapblock.h" -#include "serverobject.h" -#include "genericobject.h" +#include "server/serveractiveobject.h" #include "settings.h" #include "profiler.h" #include "log.h" @@ -48,7 +47,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen/mg_biome.h" #include "content_mapnode.h" #include "content_nodemeta.h" -#include "content_sao.h" #include "content/mods.h" #include "modchannels.h" #include "serverlist.h" @@ -65,6 +63,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "chatmessage.h" #include "chat_interface.h" #include "remoteplayer.h" +#include "server/player_sao.h" class ClientNotFoundException : public BaseException { @@ -93,6 +92,15 @@ void *ServerThread::run() { BEGIN_DEBUG_EXCEPTION_HANDLER + /* + * The real business of the server happens on the ServerThread. + * How this works: + * AsyncRunStep() runs an actual server step as soon as enough time has + * passed (dedicated_server_loop keeps track of that). + * Receive() blocks at least(!) 30ms waiting for a packet (so this loop + * doesn't busy wait) and will process any remaining packets. + */ + m_server->AsyncRunStep(true); while (!stopRequested()) { @@ -101,7 +109,6 @@ void *ServerThread::run() m_server->Receive(); - } catch (con::NoIncomingDataException &e) { } catch (con::PeerNotFoundException &e) { infostream<<"Server: PeerNotFoundException"< paths; fs::GetRecursiveDirs(paths, g_settings->get("texture_path")); fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures"); - for (const std::string &path : paths) - m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt"); + for (const std::string &path : paths) { + TextureOverrideSource override_source(path + DIR_DELIM + "override.txt"); + m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides()); + m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides()); + } m_nodedef->setNodeRegistrationStatus(true); @@ -620,134 +635,40 @@ void Server::AsyncRunStep(bool initial_step) m_clients.lock(); const RemoteClientMap &clients = m_clients.getClientList(); - ScopeProfiler sp(g_profiler, "Server: update visible objects"); - - // Radius inside which objects are active - static thread_local const s16 radius = - g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE; - - // Radius inside which players are active - static thread_local const bool is_transfer_limited = - g_settings->exists("unlimited_player_transfer_distance") && - !g_settings->getBool("unlimited_player_transfer_distance"); - static thread_local const s16 player_transfer_dist = - g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE; - s16 player_radius = player_transfer_dist; - if (player_radius == 0 && is_transfer_limited) - player_radius = radius; + ScopeProfiler sp(g_profiler, "Server: update objects within range"); for (const auto &client_it : clients) { RemoteClient *client = client_it.second; - // If definitions and textures have not been sent, don't - // send objects either if (client->getState() < CS_DefinitionsSent) continue; - RemotePlayer *player = m_env->getPlayer(client->peer_id); - if (!player) { - // This can happen if the client timeouts somehow + // This can happen if the client times out somehow + if (!m_env->getPlayer(client->peer_id)) continue; - } - PlayerSAO *playersao = player->getPlayerSAO(); + PlayerSAO *playersao = getPlayerSAO(client->peer_id); if (!playersao) continue; - s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE); - if (my_radius <= 0) my_radius = radius; - //infostream << "Server: Active Radius " << my_radius << std::endl; - - std::queue removed_objects; - std::queue added_objects; - m_env->getRemovedActiveObjects(playersao, my_radius, player_radius, - client->m_known_objects, removed_objects); - m_env->getAddedActiveObjects(playersao, my_radius, player_radius, - client->m_known_objects, added_objects); - - // Ignore if nothing happened - if (removed_objects.empty() && added_objects.empty()) { - continue; - } - - std::string data_buffer; - - char buf[4]; - - // Handle removed objects - writeU16((u8*)buf, removed_objects.size()); - data_buffer.append(buf, 2); - while (!removed_objects.empty()) { - // Get object - u16 id = removed_objects.front(); - ServerActiveObject* obj = m_env->getActiveObject(id); - - // Add to data buffer for sending - writeU16((u8*)buf, id); - data_buffer.append(buf, 2); - - // Remove from known objects - client->m_known_objects.erase(id); - - if(obj && obj->m_known_by_count > 0) - obj->m_known_by_count--; - removed_objects.pop(); - } - - // Handle added objects - writeU16((u8*)buf, added_objects.size()); - data_buffer.append(buf, 2); - while (!added_objects.empty()) { - // Get object - u16 id = added_objects.front(); - ServerActiveObject* obj = m_env->getActiveObject(id); - - // Get object type - u8 type = ACTIVEOBJECT_TYPE_INVALID; - if (!obj) - warningstream << FUNCTION_NAME << ": NULL object" << std::endl; - else - type = obj->getSendType(); - - // Add to data buffer for sending - writeU16((u8*)buf, id); - data_buffer.append(buf, 2); - writeU8((u8*)buf, type); - data_buffer.append(buf, 1); - - if(obj) - data_buffer.append(serializeLongString( - obj->getClientInitializationData(client->net_proto_version))); - else - data_buffer.append(serializeLongString("")); - - // Add to known objects - client->m_known_objects.insert(id); - - if(obj) - obj->m_known_by_count++; - - added_objects.pop(); - } - - u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer); - verbosestream << "Server: Sent object remove/add: " - << removed_objects.size() << " removed, " - << added_objects.size() << " added, " - << "packet size is " << pktSize << std::endl; + SendActiveObjectRemoveAdd(client, playersao); } m_clients.unlock(); + // Save mod storages if modified m_mod_storage_save_timer -= dtime; if (m_mod_storage_save_timer <= 0.0f) { - infostream << "Saving registered mod storages." << std::endl; m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval"); + int n = 0; for (std::unordered_map::const_iterator it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) { if (it->second->isModified()) { it->second->save(getModStoragePath()); + n++; } } + if (n > 0) + infostream << "Saved " << n << " modified mod storages." << std::endl; } } @@ -786,19 +707,33 @@ void Server::AsyncRunStep(bool initial_step) // Route data to every client for (const auto &client_it : clients) { RemoteClient *client = client_it.second; + PlayerSAO *player = getPlayerSAO(client->peer_id); std::string reliable_data; std::string unreliable_data; // Go through all objects in message buffer for (const auto &buffered_message : buffered_messages) { - // If object is not known by client, skip it + // If object does not exist or is not known by client, skip it u16 id = buffered_message.first; - if (client->m_known_objects.find(id) == client->m_known_objects.end()) + ServerActiveObject *sao = m_env->getActiveObject(id); + if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end()) continue; // Get message list of object std::vector* list = buffered_message.second; // Go through every message for (const ActiveObjectMessage &aom : *list) { + // Send position updates to players who do not see the attachment + if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) { + if (sao->getId() == player->getId()) + continue; + + // Do not send position updates for attached players + // as long the parent is known to the client + ServerActiveObject *parent = sao->getParent(); + if (parent && client->m_known_objects.find(parent->getId()) != + client->m_known_objects.end()) + continue; + } // Compose the full new data with header std::string new_data; // Add object id @@ -879,7 +814,6 @@ void Server::AsyncRunStep(bool initial_step) disable_single_change_sending ? 5 : 30); break; case MEET_BLOCK_NODE_METADATA_CHANGED: { - verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl; prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1); if (!event->is_private_change) { // Don't send the change yet. Collect them to eliminate dupes. @@ -895,7 +829,6 @@ void Server::AsyncRunStep(bool initial_step) break; } case MEET_OTHER: - infostream << "Server: MEET_OTHER" << std::endl; prof.add("MEET_OTHER", 1); for (const v3s16 &modified_block : event->modified_blocks) { m_clients.markBlockposAsNotSent(modified_block); @@ -989,24 +922,43 @@ void Server::AsyncRunStep(bool initial_step) void Server::Receive() { - session_t peer_id = 0; - try { - NetworkPacket pkt; - m_con->Receive(&pkt); - peer_id = pkt.getPeerId(); - ProcessData(&pkt); - } catch (const con::InvalidIncomingDataException &e) { - infostream << "Server::Receive(): InvalidIncomingDataException: what()=" - << e.what() << std::endl; - } catch (const SerializationError &e) { - infostream << "Server::Receive(): SerializationError: what()=" - << e.what() << std::endl; - } catch (const ClientStateError &e) { - errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl; - DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect." - L"Try reconnecting or updating your client"); - } catch (const con::PeerNotFoundException &e) { - // Do nothing + NetworkPacket pkt; + session_t peer_id; + bool first = true; + for (;;) { + pkt.clear(); + peer_id = 0; + try { + /* + In the first iteration *wait* for a packet, afterwards process + all packets that are immediately available (no waiting). + */ + if (first) { + m_con->Receive(&pkt); + first = false; + } else { + if (!m_con->TryReceive(&pkt)) + return; + } + + peer_id = pkt.getPeerId(); + ProcessData(&pkt); + } catch (const con::InvalidIncomingDataException &e) { + infostream << "Server::Receive(): InvalidIncomingDataException: what()=" + << e.what() << std::endl; + } catch (const SerializationError &e) { + infostream << "Server::Receive(): SerializationError: what()=" + << e.what() << std::endl; + } catch (const ClientStateError &e) { + errorstream << "ProcessData: peer=" << peer_id << " what()=" + << e.what() << std::endl; + DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect." + L"Try reconnecting or updating your client"); + } catch (const con::PeerNotFoundException &e) { + // Do nothing + } catch (const con::NoIncomingDataException &e) { + return; + } } } @@ -1069,16 +1021,15 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id) // Send Breath SendPlayerBreath(playersao); - Address addr = getPeerAddress(player->getPeerId()); - std::string ip_str = addr.serializeString(); - actionstream<getName() <<" [" << ip_str << "] joins game. " << std::endl; /* Print out action */ { + Address addr = getPeerAddress(player->getPeerId()); + std::string ip_str = addr.serializeString(); const std::vector &names = m_clients.getPlayerNames(); - actionstream << player->getName() << " joins game. List of players: "; + actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: "; for (const std::string &name : names) { actionstream << name << " "; @@ -1089,9 +1040,9 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id) return playersao; } -inline void Server::handleCommand(NetworkPacket* pkt) +inline void Server::handleCommand(NetworkPacket *pkt) { - const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()]; + const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()]; (this->*opHandle.handler)(pkt); } @@ -1187,12 +1138,12 @@ void Server::setTimeOfDay(u32 time) m_time_of_day_send_timer = 0; } -void Server::onMapEditEvent(MapEditEvent *event) +void Server::onMapEditEvent(const MapEditEvent &event) { - if (m_ignore_map_edit_events_area.contains(event->getArea())) + if (m_ignore_map_edit_events_area.contains(event.getArea())) return; - MapEditEvent *e = event->clone(); - m_unsent_map_edit_queue.push(e); + + m_unsent_map_edit_queue.push(new MapEditEvent(event)); } Inventory* Server::getInventory(const InventoryLocation &loc) @@ -1248,6 +1199,7 @@ void Server::setInventoryModified(const InventoryLocation &loc) return; player->setModified(true); + player->inventory.setModified(true); // Updates are sent in ServerEnvironment::step() } break; @@ -1256,7 +1208,7 @@ void Server::setInventoryModified(const InventoryLocation &loc) MapEditEvent event; event.type = MEET_BLOCK_NODE_METADATA_CHANGED; event.p = loc.p; - m_env->getMap().dispatchEvent(&event); + m_env->getMap().dispatchEvent(event); } break; case InventoryLocation::DETACHED: @@ -1333,7 +1285,7 @@ bool Server::getClientInfo( *major = client->getMajor(); *minor = client->getMinor(); *patch = client->getPatch(); - *vers_string = client->getPatch(); + *vers_string = client->getFull(); m_clients.unlock(); @@ -1568,7 +1520,7 @@ void Server::SendChatMessage(session_t peer_id, const ChatMessage &message) void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec, const std::string &formname) { - NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id); + NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id); if (formspec.empty()){ //the client should close the formspec //but make sure there wasn't another one open in meantime @@ -1579,7 +1531,7 @@ void Server::SendShowFormspecMessage(session_t peer_id, const std::string &forms pkt.putLongString(""); } else { m_formspec_state_data[peer_id] = formname; - pkt.putLongString(FORMSPEC_VERSION_STRING + formspec); + pkt.putLongString(formspec); } pkt << formname; @@ -1704,7 +1656,8 @@ void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form) pkt << id << (u8) form->type << form->pos << form->name << form->scale << form->text << form->number << form->item << form->dir - << form->align << form->offset << form->world_pos << form->size; + << form->align << form->offset << form->world_pos << form->size + << form->z_index; Send(&pkt); } @@ -1767,17 +1720,62 @@ void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &va Send(&pkt); } -void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor, - const std::string &type, const std::vector ¶ms, - bool &clouds) +void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms) { NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id); - pkt << bgcolor << type << (u16) params.size(); - for (const std::string ¶m : params) - pkt << param; + // Handle prior clients here + if (m_clients.getProtocolVersion(peer_id) < 39) { + pkt << params.bgcolor << params.type << (u16) params.textures.size(); + + for (const std::string& texture : params.textures) + pkt << texture; + + pkt << params.clouds; + } else { // Handle current clients and future clients + pkt << params.bgcolor << params.type + << params.clouds << params.sun_tint + << params.moon_tint << params.tint_type; + + if (params.type == "skybox") { + pkt << (u16) params.textures.size(); + for (const std::string &texture : params.textures) + pkt << texture; + } else if (params.type == "regular") { + pkt << params.sky_color.day_sky << params.sky_color.day_horizon + << params.sky_color.dawn_sky << params.sky_color.dawn_horizon + << params.sky_color.night_sky << params.sky_color.night_horizon + << params.sky_color.indoors; + } + } - pkt << clouds; + Send(&pkt); +} + +void Server::SendSetSun(session_t peer_id, const SunParams ¶ms) +{ + NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id); + pkt << params.visible << params.texture + << params.tonemap << params.sunrise + << params.sunrise_visible << params.scale; + + Send(&pkt); +} +void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms) +{ + NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id); + + pkt << params.visible << params.texture + << params.tonemap << params.scale; + + Send(&pkt); +} +void Server::SendSetStars(session_t peer_id, const StarParams ¶ms) +{ + NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id); + + pkt << params.visible << params.count + << params.starcolor << params.scale; Send(&pkt); } @@ -1817,18 +1815,13 @@ void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed) void Server::SendPlayerHP(session_t peer_id) { PlayerSAO *playersao = getPlayerSAO(peer_id); - // In some rare case if the player is disconnected - // while Lua call l_punch, for example, this can be NULL - if (!playersao) - return; + assert(playersao); SendHP(peer_id, playersao->getHP()); m_script->player_event(playersao,"health_changed"); // Send to other clients - std::string str = gob_cmd_punched(playersao->getHP()); - ActiveObjectMessage aom(playersao->getId(), true, str); - playersao->m_messages_out.push(aom); + playersao->sendPunchCommand(); } void Server::SendPlayerBreath(PlayerSAO *sao) @@ -1861,6 +1854,16 @@ void Server::SendMovePlayer(session_t peer_id) Send(&pkt); } +void Server::SendPlayerFov(session_t peer_id) +{ + NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id); + + PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov(); + pkt << fov_spec.fov << fov_spec.is_multiplier; + + Send(&pkt); +} + void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4], f32 animation_speed) { @@ -1908,7 +1911,8 @@ void Server::SendPlayerInventoryFormspec(session_t peer_id) return; NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id); - pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec); + pkt.putLongString(player->inventory_formspec); + Send(&pkt); } @@ -1920,16 +1924,107 @@ void Server::SendPlayerFormspecPrepend(session_t peer_id) return; NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id); - pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend; + pkt << player->formspec_prepend; Send(&pkt); } -u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas) +void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao) { - NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id); - pkt.putRawString(datas.c_str(), datas.size()); + // Radius inside which objects are active + static thread_local const s16 radius = + g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE; + + // Radius inside which players are active + static thread_local const bool is_transfer_limited = + g_settings->exists("unlimited_player_transfer_distance") && + !g_settings->getBool("unlimited_player_transfer_distance"); + + static thread_local const s16 player_transfer_dist = + g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE; + + s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ? + radius : player_transfer_dist; + + s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE); + if (my_radius <= 0) + my_radius = radius; + + std::queue removed_objects, added_objects; + m_env->getRemovedActiveObjects(playersao, my_radius, player_radius, + client->m_known_objects, removed_objects); + m_env->getAddedActiveObjects(playersao, my_radius, player_radius, + client->m_known_objects, added_objects); + + int removed_count = removed_objects.size(); + int added_count = added_objects.size(); + + if (removed_objects.empty() && added_objects.empty()) + return; + + char buf[4]; + std::string data; + + // Handle removed objects + writeU16((u8*)buf, removed_objects.size()); + data.append(buf, 2); + while (!removed_objects.empty()) { + // Get object + u16 id = removed_objects.front(); + ServerActiveObject* obj = m_env->getActiveObject(id); + + // Add to data buffer for sending + writeU16((u8*)buf, id); + data.append(buf, 2); + + // Remove from known objects + client->m_known_objects.erase(id); + + if (obj && obj->m_known_by_count > 0) + obj->m_known_by_count--; + + removed_objects.pop(); + } + + // Handle added objects + writeU16((u8*)buf, added_objects.size()); + data.append(buf, 2); + while (!added_objects.empty()) { + // Get object + u16 id = added_objects.front(); + ServerActiveObject *obj = m_env->getActiveObject(id); + added_objects.pop(); + + if (!obj) { + warningstream << FUNCTION_NAME << ": NULL object id=" + << (int)id << std::endl; + continue; + } + + // Get object type + u8 type = obj->getSendType(); + + // Add to data buffer for sending + writeU16((u8*)buf, id); + data.append(buf, 2); + writeU8((u8*)buf, type); + data.append(buf, 1); + + data.append(serializeLongString( + obj->getClientInitializationData(client->net_proto_version))); + + // Add to known objects + client->m_known_objects.insert(id); + + obj->m_known_by_count++; + } + + NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id); + pkt.putRawString(data.c_str(), data.size()); Send(&pkt); - return pkt.getSize(); + + verbosestream << "Server::SendActiveObjectRemoveAdd: " + << removed_count << " removed, " << added_count << " added, " + << "packet size is " << pkt.getSize() << std::endl; } void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas, @@ -1960,8 +2055,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; @@ -1972,7 +2077,7 @@ s32 Server::playSound(const SimpleSoundSpec &spec, // Filter destination clients std::vector 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 \""<getPlayer(client_id); if (!player) continue; + if (!params.exclude_player.empty() && + params.exclude_player == player->getName()) + continue; PlayerSAO *sao = player->getPlayerSAO(); if (!sao) @@ -2010,27 +2118,32 @@ s32 Server::playSound(const SimpleSoundSpec &spec, 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; - psound.spec = spec; + 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; + } 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; } @@ -2423,9 +2536,6 @@ void Server::fillMediaCache() void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code) { - verbosestream << "Server: Announcing files to id(" << peer_id << ")" - << std::endl; - // Make packet NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id); @@ -2448,6 +2558,9 @@ void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_co pkt << g_settings->get("remote_media"); Send(&pkt); + + verbosestream << "Server: Announcing files to id(" << peer_id + << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl; } struct SendableMedia @@ -2630,10 +2743,7 @@ void Server::sendDetachedInventories(session_t peer_id, bool incremental) void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason) { PlayerSAO *playersao = getPlayerSAO(peer_id); - // In some rare cases this can be NULL -- if the player is disconnected - // when a Lua function modifies l_punch, for example - if (!playersao) - return; + assert(playersao); infostream << "Server::DiePlayer(): Player " << playersao->getPlayer()->getName() @@ -2829,10 +2939,8 @@ void Server::UpdateCrafting(RemotePlayer *player) if (!clist || clist->getSize() == 0) return; - if (!clist->checkModified()) { - verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl; + if (!clist->checkModified()) return; - } // Get a preview for crafting ItemStack preview; @@ -3255,13 +3363,32 @@ void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3 SendEyeOffset(player->getPeerId(), first, third); } -void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor, - const std::string &type, const std::vector ¶ms, - bool &clouds) +void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms) { sanity_check(player); - player->setSky(bgcolor, type, params, clouds); - SendSetSky(player->getPeerId(), bgcolor, type, params, clouds); + player->setSky(params); + SendSetSky(player->getPeerId(), params); +} + +void Server::setSun(RemotePlayer *player, const SunParams ¶ms) +{ + sanity_check(player); + player->setSun(params); + SendSetSun(player->getPeerId(), params); +} + +void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms) +{ + sanity_check(player); + player->setMoon(params); + SendSetMoon(player->getPeerId(), params); +} + +void Server::setStars(RemotePlayer *player, const StarParams ¶ms) +{ + sanity_check(player); + player->setStars(params); + SendSetStars(player->getPeerId(), params); } void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms) @@ -3703,6 +3830,11 @@ void dedicated_server_loop(Server &server, bool &kill) static thread_local const float profiler_print_interval = g_settings->getFloat("profiler_print_interval"); + /* + * The dedicated server loop only does time-keeping (in Server::step) and + * provides a way to main.cpp to kill the server externally (bool &kill). + */ + for(;;) { // This is kind of a hack but can be done like this // because server.step() is very light