]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/network/clientpackethandler.cpp
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / src / network / clientpackethandler.cpp
index 373d4484a8d8a81a57557fb1214209899c9d2e9e..29e3364db0e2d6ef4a50b365832076702820c0be 100644 (file)
@@ -45,6 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "tileanimation.h"
 #include "gettext.h"
 #include "skyparams.h"
+#include <memory>
 
 void Client::handleCommand_Deprecated(NetworkPacket* pkt)
 {
@@ -90,7 +91,7 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
        // This is only neccessary though when we actually want to add casing support
 
        if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
-               // we recieved a TOCLIENT_HELLO while auth was already going on
+               // we received a TOCLIENT_HELLO while auth was already going on
                errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
                        << "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
                if (m_chosen_auth_mech == AUTH_MECHANISM_SRP ||
@@ -158,7 +159,7 @@ void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
 
        m_password = m_new_password;
 
-       verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
+       verbosestream << "Client: Received TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
 
        // send packet to actually set the password
        startAuth(AUTH_MECHANISM_FIRST_SRP);
@@ -184,7 +185,7 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
        m_access_denied_reason = "Unknown";
 
        if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) {
-               // 13/03/15 Legacy code from 0.4.12 and lesser but is still used
+               // Legacy code from 0.4.12 and older but is still used
                // in some places of the server code
                if (pkt->getSize() >= 2) {
                        std::wstring wide_reason;
@@ -197,14 +198,14 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
        if (pkt->getSize() < 1)
                return;
 
-       u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
+       u8 denyCode;
        *pkt >> denyCode;
+
        if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN ||
                        denyCode == SERVER_ACCESSDENIED_CRASH) {
                *pkt >> m_access_denied_reason;
-               if (m_access_denied_reason.empty()) {
+               if (m_access_denied_reason.empty())
                        m_access_denied_reason = accessDeniedStrings[denyCode];
-               }
                u8 reconnect;
                *pkt >> reconnect;
                m_access_denied_reconnect = reconnect & 1;
@@ -221,9 +222,8 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
                // Until then (which may be never), this is outside
                // of the defined protocol.
                *pkt >> m_access_denied_reason;
-               if (m_access_denied_reason.empty()) {
+               if (m_access_denied_reason.empty())
                        m_access_denied_reason = "Unknown";
-               }
        }
 }
 
@@ -263,7 +263,7 @@ void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt)
                return;
 
        std::istringstream is(pkt->readLongString(), std::ios::binary);
-       std::stringstream sstr;
+       std::stringstream sstr(std::ios::binary | std::ios::in | std::ios::out);
        decompressZlib(is, sstr);
 
        NodeMetadataList meta_updates_list(false);
@@ -684,21 +684,19 @@ void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
                m_media_downloader->addFile(name, sha1_raw);
        }
 
-       try {
+       {
                std::string str;
-
                *pkt >> str;
 
                Strfnd sf(str);
-               while(!sf.at_end()) {
+               while (!sf.at_end()) {
                        std::string baseurl = trim(sf.next(","));
-                       if (!baseurl.empty())
+                       if (!baseurl.empty()) {
+                               m_remote_media_servers.emplace_back(baseurl);
                                m_media_downloader->addRemoteServer(baseurl);
+                       }
                }
        }
-       catch(SerializationError& e) {
-               // not supported by server or turned off
-       }
 
        m_media_downloader->step(this);
 }
@@ -730,31 +728,38 @@ void Client::handleCommand_Media(NetworkPacket* pkt)
        if (num_files == 0)
                return;
 
-       if (!m_media_downloader || !m_media_downloader->isStarted()) {
-               const char *problem = m_media_downloader ?
-                       "media has not been requested" :
-                       "all media has been received already";
-               errorstream << "Client: Received media but "
-                       << problem << "! "
-                       << " bunch " << bunch_i << "/" << num_bunches
-                       << " files=" << num_files
-                       << " size=" << pkt->getSize() << std::endl;
-               return;
-       }
+       bool init_phase = m_media_downloader && m_media_downloader->isStarted();
 
-       // Mesh update thread must be stopped while
-       // updating content definitions
-       sanity_check(!m_mesh_update_thread.isRunning());
+       if (init_phase) {
+               // Mesh update thread must be stopped while
+               // updating content definitions
+               sanity_check(!m_mesh_update_thread.isRunning());
+       }
 
-       for (u32 i=0; i < num_files; i++) {
-               std::string name;
+       for (u32 i = 0; i < num_files; i++) {
+               std::string name, data;
 
                *pkt >> name;
+               data = pkt->readLongString();
 
-               std::string data = pkt->readLongString();
-
-               m_media_downloader->conventionalTransferDone(
-                               name, data, this);
+               bool ok = false;
+               if (init_phase) {
+                       ok = m_media_downloader->conventionalTransferDone(name, data, this);
+               } else {
+                       // Check pending dynamic transfers, one of them must be it
+                       for (const auto &it : m_pending_media_downloads) {
+                               if (it.second->conventionalTransferDone(name, data, this)) {
+                                       ok = true;
+                                       break;
+                               }
+                       }
+               }
+               if (!ok) {
+                       errorstream << "Client: Received media \"" << name
+                               << "\" but no downloads pending. " << num_bunches << " bunches, "
+                               << num_files << " in this one. (init_phase=" << init_phase
+                               << ")" << std::endl;
+               }
        }
 }
 
@@ -769,12 +774,11 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
 
        // Decompress node definitions
        std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
-       std::ostringstream tmp_os;
+       std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
        decompressZlib(tmp_is, tmp_os);
 
        // Deserialize node definitions
-       std::istringstream tmp_is2(tmp_os.str());
-       m_nodedef->deSerialize(tmp_is2);
+       m_nodedef->deSerialize(tmp_os);
        m_nodedef_received = true;
 }
 
@@ -789,12 +793,11 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
 
        // Decompress item definitions
        std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
-       std::ostringstream tmp_os;
+       std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
        decompressZlib(tmp_is, tmp_os);
 
        // Deserialize node definitions
-       std::istringstream tmp_is2(tmp_os.str());
-       m_itemdef->deSerialize(tmp_is2);
+       m_itemdef->deSerialize(tmp_os);
        m_itemdef_received = true;
 }
 
@@ -1063,9 +1066,6 @@ void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
 
 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
 {
-       std::string datastring(pkt->getString(0), pkt->getSize());
-       std::istringstream is(datastring, std::ios_base::binary);
-
        u32 server_id;
        u8 type;
        v2f pos;
@@ -1081,6 +1081,7 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt)
        v2s32 size;
        s16 z_index = 0;
        std::string text2;
+       u32 style = 0;
 
        *pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item
                >> dir >> align >> offset;
@@ -1089,25 +1090,28 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt)
                *pkt >> size;
                *pkt >> z_index;
                *pkt >> text2;
+               *pkt >> style;
        } catch(PacketError &e) {};
 
        ClientEvent *event = new ClientEvent();
-       event->type             = CE_HUDADD;
-       event->hudadd.server_id = server_id;
-       event->hudadd.type      = type;
-       event->hudadd.pos       = new v2f(pos);
-       event->hudadd.name      = new std::string(name);
-       event->hudadd.scale     = new v2f(scale);
-       event->hudadd.text      = new std::string(text);
-       event->hudadd.number    = number;
-       event->hudadd.item      = item;
-       event->hudadd.dir       = dir;
-       event->hudadd.align     = new v2f(align);
-       event->hudadd.offset    = new v2f(offset);
-       event->hudadd.world_pos = new v3f(world_pos);
-       event->hudadd.size      = new v2s32(size);
-       event->hudadd.z_index   = z_index;
-       event->hudadd.text2     = new std::string(text2);
+       event->type              = CE_HUDADD;
+       event->hudadd            = new ClientEventHudAdd();
+       event->hudadd->server_id = server_id;
+       event->hudadd->type      = type;
+       event->hudadd->pos       = pos;
+       event->hudadd->name      = name;
+       event->hudadd->scale     = scale;
+       event->hudadd->text      = text;
+       event->hudadd->number    = number;
+       event->hudadd->item      = item;
+       event->hudadd->dir       = dir;
+       event->hudadd->align     = align;
+       event->hudadd->offset    = offset;
+       event->hudadd->world_pos = world_pos;
+       event->hudadd->size      = size;
+       event->hudadd->z_index   = z_index;
+       event->hudadd->text2     = text2;
+       event->hudadd->style     = style;
        m_client_event_queue.push(event);
 }
 
@@ -1117,16 +1121,10 @@ void Client::handleCommand_HudRemove(NetworkPacket* pkt)
 
        *pkt >> server_id;
 
-       auto i = m_hud_server_to_client.find(server_id);
-       if (i != m_hud_server_to_client.end()) {
-               int client_id = i->second;
-               m_hud_server_to_client.erase(i);
-
-               ClientEvent *event = new ClientEvent();
-               event->type     = CE_HUDRM;
-               event->hudrm.id = client_id;
-               m_client_event_queue.push(event);
-       }
+       ClientEvent *event = new ClientEvent();
+       event->type     = CE_HUDRM;
+       event->hudrm.id = server_id;
+       m_client_event_queue.push(event);
 }
 
 void Client::handleCommand_HudChange(NetworkPacket* pkt)
@@ -1141,31 +1139,41 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt)
 
        *pkt >> server_id >> stat;
 
-       if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
-               stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
-               *pkt >> v2fdata;
-       else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT || stat == HUD_STAT_TEXT2)
-               *pkt >> sdata;
-       else if (stat == HUD_STAT_WORLD_POS)
-               *pkt >> v3fdata;
-       else if (stat == HUD_STAT_SIZE )
-               *pkt >> v2s32data;
-       else
-               *pkt >> intdata;
-
-       std::unordered_map<u32, u32>::const_iterator i = m_hud_server_to_client.find(server_id);
-       if (i != m_hud_server_to_client.end()) {
-               ClientEvent *event = new ClientEvent();
-               event->type              = CE_HUDCHANGE;
-               event->hudchange.id      = i->second;
-               event->hudchange.stat    = (HudElementStat)stat;
-               event->hudchange.v2fdata = new v2f(v2fdata);
-               event->hudchange.v3fdata = new v3f(v3fdata);
-               event->hudchange.sdata   = new std::string(sdata);
-               event->hudchange.data    = intdata;
-               event->hudchange.v2s32data = new v2s32(v2s32data);
-               m_client_event_queue.push(event);
+       // Keep in sync with:server.cpp -> SendHUDChange
+       switch ((HudElementStat)stat) {
+               case HUD_STAT_POS:
+               case HUD_STAT_SCALE:
+               case HUD_STAT_ALIGN:
+               case HUD_STAT_OFFSET:
+                       *pkt >> v2fdata;
+                       break;
+               case HUD_STAT_NAME:
+               case HUD_STAT_TEXT:
+               case HUD_STAT_TEXT2:
+                       *pkt >> sdata;
+                       break;
+               case HUD_STAT_WORLD_POS:
+                       *pkt >> v3fdata;
+                       break;
+               case HUD_STAT_SIZE:
+                       *pkt >> v2s32data;
+                       break;
+               default:
+                       *pkt >> intdata;
+                       break;
        }
+
+       ClientEvent *event = new ClientEvent();
+       event->type                 = CE_HUDCHANGE;
+       event->hudchange            = new ClientEventHudChange();
+       event->hudchange->id        = server_id;
+       event->hudchange->stat      = static_cast<HudElementStat>(stat);
+       event->hudchange->v2fdata   = v2fdata;
+       event->hudchange->v3fdata   = v3fdata;
+       event->hudchange->sdata     = sdata;
+       event->hudchange->data      = intdata;
+       event->hudchange->v2s32data = v2s32data;
+       m_client_event_queue.push(event);
 }
 
 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
@@ -1256,19 +1264,17 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
                } catch (...) {}
 
                // Use default skybox settings:
-               SkyboxDefaults sky_defaults;
-               SunParams sun = sky_defaults.getSunDefaults();
-               MoonParams moon = sky_defaults.getMoonDefaults();
-               StarParams stars = sky_defaults.getStarDefaults();
+               SunParams sun = SkyboxDefaults::getSunDefaults();
+               MoonParams moon = SkyboxDefaults::getMoonDefaults();
+               StarParams stars = SkyboxDefaults::getStarDefaults();
 
                // Fix for "regular" skies, as color isn't kept:
                if (skybox.type == "regular") {
-                       skybox.sky_color = sky_defaults.getSkyColorDefaults();
+                       skybox.sky_color = SkyboxDefaults::getSkyColorDefaults();
                        skybox.fog_tint_type = "default";
                        skybox.fog_moon_tint = video::SColor(255, 255, 255, 255);
                        skybox.fog_sun_tint = video::SColor(255, 255, 255, 255);
-               }
-               else {
+               } else {
                        sun.visible = false;
                        sun.sunrise_visible = false;
                        moon.visible = false;
@@ -1418,6 +1424,8 @@ void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
        *pkt >> player->local_animations[2];
        *pkt >> player->local_animations[3];
        *pkt >> player->local_animation_speed;
+
+       player->last_animation = -1;
 }
 
 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
@@ -1517,46 +1525,72 @@ void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
 void Client::handleCommand_MediaPush(NetworkPacket *pkt)
 {
        std::string raw_hash, filename, filedata;
+       u32 token;
        bool cached;
 
        *pkt >> raw_hash >> filename >> cached;
-       filedata = pkt->readLongString();
+       if (m_proto_ver >= 40)
+               *pkt >> token;
+       else
+               filedata = pkt->readLongString();
 
-       if (raw_hash.size() != 20 || filedata.empty() || filename.empty() ||
+       if (raw_hash.size() != 20 || filename.empty() ||
+                       (m_proto_ver < 40 && filedata.empty()) ||
                        !string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
                throw PacketError("Illegal filename, data or hash");
        }
 
-       verbosestream << "Server pushes media file \"" << filename << "\" with "
-               << filedata.size() << " bytes of data (cached=" << cached
-               << ")" << std::endl;
+       verbosestream << "Server pushes media file \"" << filename << "\" ";
+       if (filedata.empty())
+               verbosestream << "to be fetched ";
+       else
+               verbosestream << "with " << filedata.size() << " bytes ";
+       verbosestream << "(cached=" << cached << ")" << std::endl;
 
        if (m_media_pushed_files.count(filename) != 0) {
-               // Silently ignore for synchronization purposes
+               // Ignore (but acknowledge). Previously this was for sync purposes,
+               // but even in new versions media cannot be replaced at runtime.
+               if (m_proto_ver >= 40)
+                       sendHaveMedia({ token });
                return;
        }
 
-       // Compute and check checksum of data
-       std::string computed_hash;
-       {
-               SHA1 ctx;
-               ctx.addBytes(filedata.c_str(), filedata.size());
-               unsigned char *buf = ctx.getDigest();
-               computed_hash.assign((char*) buf, 20);
-               free(buf);
-       }
-       if (raw_hash != computed_hash) {
-               verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
+       if (!filedata.empty()) {
+               // LEGACY CODEPATH
+               // Compute and check checksum of data
+               std::string computed_hash;
+               {
+                       SHA1 ctx;
+                       ctx.addBytes(filedata.c_str(), filedata.size());
+                       unsigned char *buf = ctx.getDigest();
+                       computed_hash.assign((char*) buf, 20);
+                       free(buf);
+               }
+               if (raw_hash != computed_hash) {
+                       verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
+                       return;
+               }
+
+               // Actually load media
+               loadMedia(filedata, filename, true);
+               m_media_pushed_files.insert(filename);
+
+               // Cache file for the next time when this client joins the same server
+               if (cached)
+                       clientMediaUpdateCache(raw_hash, filedata);
                return;
        }
 
-       // Actually load media
-       loadMedia(filedata, filename, true);
        m_media_pushed_files.insert(filename);
 
-       // Cache file for the next time when this client joins the same server
-       if (cached)
-               clientMediaUpdateCache(raw_hash, filedata);
+       // create a downloader for this file
+       auto downloader(std::make_shared<SingleMediaDownloader>(cached));
+       m_pending_media_downloads.emplace_back(token, downloader);
+       downloader->addFile(filename, raw_hash);
+       for (const auto &baseurl : m_remote_media_servers)
+               downloader->addRemoteServer(baseurl);
+
+       downloader->step(this);
 }
 
 /*
@@ -1677,3 +1711,11 @@ void Client::handleCommand_MinimapModes(NetworkPacket *pkt)
        if (m_minimap)
                m_minimap->setModeIndex(mode);
 }
+
+void Client::handleCommand_SetLighting(NetworkPacket *pkt)
+{
+       Lighting& lighting = m_env.getLocalPlayer()->getLighting();
+
+       if (pkt->getRemainingBytes() >= 4)
+               *pkt >> lighting.shadow_intensity;
+}