]> git.lizzy.rs Git - minetest.git/blobdiff - src/server.cpp
Fix pathfinder bugs: returning nil frequently, broken A*, jump through solid nodes...
[minetest.git] / src / server.cpp
index 4aa8375c80b9d35ea55edb72b2cbab5358e28c92..c1f27149004ee33d7852955d365f0f06312dd44b 100644 (file)
@@ -93,6 +93,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 +110,6 @@ void *ServerThread::run()
 
                        m_server->Receive();
 
-               } catch (con::NoIncomingDataException &e) {
                } catch (con::PeerNotFoundException &e) {
                        infostream<<"Server: PeerNotFoundException"<<std::endl;
                } catch (ClientNotFoundException &e) {
@@ -911,24 +919,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;
+               }
        }
 }
 
@@ -1256,7 +1283,7 @@ bool Server::getClientInfo(
        *major = client->getMajor();
        *minor = client->getMinor();
        *patch = client->getPatch();
-       *vers_string = client->getPatch();
+       *vers_string = client->getFull();
 
        m_clients.unlock();
 
@@ -1627,7 +1654,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);
 }
@@ -1740,10 +1768,7 @@ 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");
@@ -1985,8 +2010,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 &params)
+               const ServerSoundParams &params, bool ephemeral)
 {
        // Find out initial position of sound
        bool pos_exists = false;
@@ -1997,7 +2032,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
@@ -2017,6 +2052,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)
@@ -2035,27 +2073,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;
 }
@@ -2655,10 +2698,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()
@@ -3728,6 +3768,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