]> git.lizzy.rs Git - minetest.git/blob - src/network/clientpackethandler.cpp
Get rid of `basic_debug` last minute
[minetest.git] / src / network / clientpackethandler.cpp
1 /*
2 Minetest
3 Copyright (C) 2015 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "client/client.h"
21
22 #include "util/base64.h"
23 #include "client/camera.h"
24 #include "chatmessage.h"
25 #include "client/clientmedia.h"
26 #include "log.h"
27 #include "map.h"
28 #include "mapsector.h"
29 #include "client/minimap.h"
30 #include "modchannels.h"
31 #include "nodedef.h"
32 #include "serialization.h"
33 #include "server.h"
34 #include "util/strfnd.h"
35 #include "client/clientevent.h"
36 #include "client/sound.h"
37 #include "network/clientopcodes.h"
38 #include "network/connection.h"
39 #include "script/scripting_client.h"
40 #include "util/serialize.h"
41 #include "util/srp.h"
42 #include "util/sha1.h"
43 #include "tileanimation.h"
44 #include "gettext.h"
45 #include "skyparams.h"
46 #include <memory>
47
48 void Client::handleCommand_Deprecated(NetworkPacket* pkt)
49 {
50         infostream << "Got deprecated command "
51                         << toClientCommandTable[pkt->getCommand()].name << " from peer "
52                         << pkt->getPeerId() << "!" << std::endl;
53 }
54
55 void Client::handleCommand_Hello(NetworkPacket* pkt)
56 {
57         if (pkt->getSize() < 1)
58                 return;
59
60         u8 serialization_ver;
61         u16 proto_ver;
62         u16 compression_mode;
63         u32 auth_mechs;
64         std::string username_legacy; // for case insensitivity
65         *pkt >> serialization_ver >> compression_mode >> proto_ver
66                 >> auth_mechs >> username_legacy;
67
68         // Chose an auth method we support
69         AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);
70
71         infostream << "Client: TOCLIENT_HELLO received with "
72                         << "serialization_ver=" << (u32)serialization_ver
73                         << ", auth_mechs=" << auth_mechs
74                         << ", proto_ver=" << proto_ver
75                         << ", compression_mode=" << compression_mode
76                         << ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
77
78         if (!ser_ver_supported(serialization_ver)) {
79                 infostream << "Client: TOCLIENT_HELLO: Server sent "
80                                 << "unsupported ser_fmt_ver"<< std::endl;
81                 return;
82         }
83
84         m_server_ser_ver = serialization_ver;
85         m_proto_ver = proto_ver;
86
87         //TODO verify that username_legacy matches sent username, only
88         // differs in casing (make both uppercase and compare)
89         // This is only neccessary though when we actually want to add casing support
90
91         if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
92                 // we received a TOCLIENT_HELLO while auth was already going on
93                 errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
94                         << "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
95                 if (m_chosen_auth_mech == AUTH_MECHANISM_SRP ||
96                                 m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD) {
97                         srp_user_delete((SRPUser *) m_auth_data);
98                         m_auth_data = 0;
99                 }
100         }
101
102         // Authenticate using that method, or abort if there wasn't any method found
103         if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
104                 if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP &&
105                                 !m_simple_singleplayer_mode &&
106                                 !getServerAddress().isLocalhost() &&
107                                 g_settings->getBool("enable_register_confirmation")) {
108                         promptConfirmRegistration(chosen_auth_mechanism);
109                 } else {
110                         startAuth(chosen_auth_mechanism);
111                 }
112         } else {
113                 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
114                 m_access_denied = true;
115                 m_access_denied_reason = "Unknown";
116                 m_con->Disconnect();
117         }
118
119 }
120
121 void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
122 {
123         deleteAuthData();
124
125         v3f playerpos;
126         *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
127                 >> m_sudo_auth_methods;
128
129         playerpos -= v3f(0, BS / 2, 0);
130
131         // Set player position
132         LocalPlayer *player = m_env.getLocalPlayer();
133         assert(player != NULL);
134         player->setPosition(playerpos);
135
136         infostream << "Client: received map seed: " << m_map_seed << std::endl;
137         infostream << "Client: received recommended send interval "
138                                         << m_recommended_send_interval<<std::endl;
139
140         // Reply to server
141         /*~ DO NOT TRANSLATE THIS LITERALLY!
142         This is a special string which needs to contain the translation's
143         language code (e.g. "de" for German). */
144         std::string lang = gettext("LANG_CODE");
145         if (lang == "LANG_CODE")
146                 lang = "";
147
148         NetworkPacket resp_pkt(TOSERVER_INIT2, sizeof(u16) + lang.size());
149         resp_pkt << lang;
150         Send(&resp_pkt);
151
152         m_state = LC_Init;
153 }
154 void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
155 {
156         deleteAuthData();
157
158         m_password = m_new_password;
159
160         verbosestream << "Client: Received TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
161
162         // send packet to actually set the password
163         startAuth(AUTH_MECHANISM_FIRST_SRP);
164
165         // reset again
166         m_chosen_auth_mech = AUTH_MECHANISM_NONE;
167 }
168 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
169 {
170         ChatMessage *chatMessage = new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
171                         L"Password change denied. Password NOT changed.");
172         pushToChatQueue(chatMessage);
173         // reset everything and be sad
174         deleteAuthData();
175 }
176
177 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
178 {
179         // The server didn't like our password. Note, this needs
180         // to be processed even if the serialisation format has
181         // not been agreed yet, the same as TOCLIENT_INIT.
182         m_access_denied = true;
183         m_access_denied_reason = "Unknown";
184
185         if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) {
186                 // 13/03/15 Legacy code from 0.4.12 and lesser but is still used
187                 // in some places of the server code
188                 if (pkt->getSize() >= 2) {
189                         std::wstring wide_reason;
190                         *pkt >> wide_reason;
191                         m_access_denied_reason = wide_to_utf8(wide_reason);
192                 }
193                 return;
194         }
195
196         if (pkt->getSize() < 1)
197                 return;
198
199         u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
200         *pkt >> denyCode;
201         if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN ||
202                         denyCode == SERVER_ACCESSDENIED_CRASH) {
203                 *pkt >> m_access_denied_reason;
204                 if (m_access_denied_reason.empty()) {
205                         m_access_denied_reason = accessDeniedStrings[denyCode];
206                 }
207                 u8 reconnect;
208                 *pkt >> reconnect;
209                 m_access_denied_reconnect = reconnect & 1;
210         } else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
211                 *pkt >> m_access_denied_reason;
212         } else if (denyCode == SERVER_ACCESSDENIED_TOO_MANY_USERS) {
213                 m_access_denied_reason = accessDeniedStrings[denyCode];
214                 m_access_denied_reconnect = true;
215         } else if (denyCode < SERVER_ACCESSDENIED_MAX) {
216                 m_access_denied_reason = accessDeniedStrings[denyCode];
217         } else {
218                 // Allow us to add new error messages to the
219                 // protocol without raising the protocol version, if we want to.
220                 // Until then (which may be never), this is outside
221                 // of the defined protocol.
222                 *pkt >> m_access_denied_reason;
223                 if (m_access_denied_reason.empty()) {
224                         m_access_denied_reason = "Unknown";
225                 }
226         }
227 }
228
229 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
230 {
231         if (pkt->getSize() < 6)
232                 return;
233
234         v3s16 p;
235         *pkt >> p;
236         removeNode(p);
237 }
238
239 void Client::handleCommand_AddNode(NetworkPacket* pkt)
240 {
241         if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
242                 return;
243
244         v3s16 p;
245         *pkt >> p;
246
247         MapNode n;
248         n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
249
250         bool remove_metadata = true;
251         u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
252         if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
253                 remove_metadata = false;
254         }
255
256         addNode(p, n, remove_metadata);
257 }
258
259 void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt)
260 {
261         if (pkt->getSize() < 1)
262                 return;
263
264         std::istringstream is(pkt->readLongString(), std::ios::binary);
265         std::stringstream sstr(std::ios::binary | std::ios::in | std::ios::out);
266         decompressZlib(is, sstr);
267
268         NodeMetadataList meta_updates_list(false);
269         meta_updates_list.deSerialize(sstr, m_itemdef, true);
270
271         Map &map = m_env.getMap();
272         for (NodeMetadataMap::const_iterator i = meta_updates_list.begin();
273                         i != meta_updates_list.end(); ++i) {
274                 v3s16 pos = i->first;
275
276                 if (map.isValidPosition(pos) &&
277                                 map.setNodeMetadata(pos, i->second))
278                         continue; // Prevent from deleting metadata
279
280                 // Meta couldn't be set, unused metadata
281                 delete i->second;
282         }
283 }
284
285 void Client::handleCommand_BlockData(NetworkPacket* pkt)
286 {
287         // Ignore too small packet
288         if (pkt->getSize() < 6)
289                 return;
290
291         v3s16 p;
292         *pkt >> p;
293
294         std::string datastring(pkt->getString(6), pkt->getSize() - 6);
295         std::istringstream istr(datastring, std::ios_base::binary);
296
297         MapSector *sector;
298         MapBlock *block;
299
300         v2s16 p2d(p.X, p.Z);
301         sector = m_env.getMap().emergeSector(p2d);
302
303         assert(sector->getPos() == p2d);
304
305         block = sector->getBlockNoCreateNoEx(p.Y);
306         if (block) {
307                 /*
308                         Update an existing block
309                 */
310                 block->deSerialize(istr, m_server_ser_ver, false);
311                 block->deSerializeNetworkSpecific(istr);
312         }
313         else {
314                 /*
315                         Create a new block
316                 */
317                 block = new MapBlock(&m_env.getMap(), p, this);
318                 block->deSerialize(istr, m_server_ser_ver, false);
319                 block->deSerializeNetworkSpecific(istr);
320                 sector->insertBlock(block);
321         }
322
323         if (m_localdb) {
324                 ServerMap::saveBlock(block, m_localdb);
325         }
326
327         /*
328                 Add it to mesh update queue and set it to be acknowledged after update.
329         */
330         addUpdateMeshTaskWithEdge(p, true);
331 }
332
333 void Client::handleCommand_Inventory(NetworkPacket* pkt)
334 {
335         if (pkt->getSize() < 1)
336                 return;
337
338         std::string datastring(pkt->getString(0), pkt->getSize());
339         std::istringstream is(datastring, std::ios_base::binary);
340
341         LocalPlayer *player = m_env.getLocalPlayer();
342         assert(player != NULL);
343
344         player->inventory.deSerialize(is);
345
346         m_update_wielded_item = true;
347
348         delete m_inventory_from_server;
349         m_inventory_from_server = new Inventory(player->inventory);
350         m_inventory_from_server_age = 0.0;
351 }
352
353 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
354 {
355         if (pkt->getSize() < 2)
356                 return;
357
358         u16 time_of_day;
359
360         *pkt >> time_of_day;
361
362         time_of_day      = time_of_day % 24000;
363         float time_speed = 0;
364
365         if (pkt->getSize() >= 2 + 4) {
366                 *pkt >> time_speed;
367         }
368         else {
369                 // Old message; try to approximate speed of time by ourselves
370                 float time_of_day_f = (float)time_of_day / 24000.0f;
371                 float tod_diff_f = 0;
372
373                 if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
374                         tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0f;
375                 else
376                         tod_diff_f = time_of_day_f - m_last_time_of_day_f;
377
378                 m_last_time_of_day_f       = time_of_day_f;
379                 float time_diff            = m_time_of_day_update_timer;
380                 m_time_of_day_update_timer = 0;
381
382                 if (m_time_of_day_set) {
383                         time_speed = (3600.0f * 24.0f) * tod_diff_f / time_diff;
384                         infostream << "Client: Measured time_of_day speed (old format): "
385                                         << time_speed << " tod_diff_f=" << tod_diff_f
386                                         << " time_diff=" << time_diff << std::endl;
387                 }
388         }
389
390         // Update environment
391         m_env.setTimeOfDay(time_of_day);
392         m_env.setTimeOfDaySpeed(time_speed);
393         m_time_of_day_set = true;
394
395         //u32 dr = m_env.getDayNightRatio();
396         //infostream << "Client: time_of_day=" << time_of_day
397         //              << " time_speed=" << time_speed
398         //              << " dr=" << dr << std::endl;
399 }
400
401 void Client::handleCommand_ChatMessage(NetworkPacket *pkt)
402 {
403         /*
404                 u8 version
405                 u8 message_type
406                 u16 sendername length
407                 wstring sendername
408                 u16 length
409                 wstring message
410          */
411
412         ChatMessage *chatMessage = new ChatMessage();
413         u8 version, message_type;
414         *pkt >> version >> message_type;
415
416         if (version != 1 || message_type >= CHATMESSAGE_TYPE_MAX) {
417                 delete chatMessage;
418                 return;
419         }
420
421         u64 timestamp;
422         *pkt >> chatMessage->sender >> chatMessage->message >> timestamp;
423         chatMessage->timestamp = static_cast<std::time_t>(timestamp);
424
425         chatMessage->type = (ChatMessageType) message_type;
426
427         // @TODO send this to CSM using ChatMessage object
428         if (modsLoaded() && m_script->on_receiving_message(
429                         wide_to_utf8(chatMessage->message))) {
430                 // Message was consumed by CSM and should not be handled by client
431                 delete chatMessage;
432         } else {
433                 pushToChatQueue(chatMessage);
434         }
435 }
436
437 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
438 {
439         /*
440                 u16 count of removed objects
441                 for all removed objects {
442                         u16 id
443                 }
444                 u16 count of added objects
445                 for all added objects {
446                         u16 id
447                         u8 type
448                         u32 initialization data length
449                         string initialization data
450                 }
451         */
452
453         try {
454                 u8 type;
455                 u16 removed_count, added_count, id;
456
457                 // Read removed objects
458                 *pkt >> removed_count;
459
460                 for (u16 i = 0; i < removed_count; i++) {
461                         *pkt >> id;
462                         m_env.removeActiveObject(id);
463                 }
464
465                 // Read added objects
466                 *pkt >> added_count;
467
468                 for (u16 i = 0; i < added_count; i++) {
469                         *pkt >> id >> type;
470                         m_env.addActiveObject(id, type, pkt->readLongString());
471                 }
472         } catch (PacketError &e) {
473                 infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
474                                 << ". The packet is unreliable, ignoring" << std::endl;
475         }
476
477         // m_activeobjects_received is false before the first
478         // TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD packet is received
479         m_activeobjects_received = true;
480 }
481
482 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
483 {
484         /*
485                 for all objects
486                 {
487                         u16 id
488                         u16 message length
489                         string message
490                 }
491         */
492         std::string datastring(pkt->getString(0), pkt->getSize());
493         std::istringstream is(datastring, std::ios_base::binary);
494
495         try {
496                 while (is.good()) {
497                         u16 id = readU16(is);
498                         if (!is.good())
499                                 break;
500
501                         std::string message = deSerializeString16(is);
502
503                         // Pass on to the environment
504                         m_env.processActiveObjectMessage(id, message);
505                 }
506         } catch (SerializationError &e) {
507                 errorstream << "Client::handleCommand_ActiveObjectMessages: "
508                         << "caught SerializationError: " << e.what() << std::endl;
509         }
510 }
511
512 void Client::handleCommand_Movement(NetworkPacket* pkt)
513 {
514         LocalPlayer *player = m_env.getLocalPlayer();
515         assert(player != NULL);
516
517         float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
518
519         *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
520                 >> lf >> lfs >> ls >> g;
521
522         player->movement_acceleration_default   = mad * BS;
523         player->movement_acceleration_air       = maa * BS;
524         player->movement_acceleration_fast      = maf * BS;
525         player->movement_speed_walk             = msw * BS;
526         player->movement_speed_crouch           = mscr * BS;
527         player->movement_speed_fast             = msf * BS;
528         player->movement_speed_climb            = mscl * BS;
529         player->movement_speed_jump             = msj * BS;
530         player->movement_liquid_fluidity        = lf * BS;
531         player->movement_liquid_fluidity_smooth = lfs * BS;
532         player->movement_liquid_sink            = ls * BS;
533         player->movement_gravity                = g * BS;
534 }
535
536 void Client::handleCommand_Fov(NetworkPacket *pkt)
537 {
538         f32 fov;
539         bool is_multiplier = false;
540         f32 transition_time = 0.0f;
541
542         *pkt >> fov >> is_multiplier;
543
544         // Wrap transition_time extraction within a
545         // try-catch to preserve backwards compat
546         try {
547                 *pkt >> transition_time;
548         } catch (PacketError &e) {};
549
550         LocalPlayer *player = m_env.getLocalPlayer();
551         assert(player);
552         player->setFov({ fov, is_multiplier, transition_time });
553         m_camera->notifyFovChange();
554 }
555
556 void Client::handleCommand_HP(NetworkPacket *pkt)
557 {
558         LocalPlayer *player = m_env.getLocalPlayer();
559         assert(player != NULL);
560
561         u16 oldhp = player->hp;
562
563         u16 hp;
564         *pkt >> hp;
565
566         player->hp = hp;
567
568         if (modsLoaded())
569                 m_script->on_hp_modification(hp);
570
571         if (hp < oldhp) {
572                 // Add to ClientEvent queue
573                 ClientEvent *event = new ClientEvent();
574                 event->type = CE_PLAYER_DAMAGE;
575                 event->player_damage.amount = oldhp - hp;
576                 m_client_event_queue.push(event);
577         }
578 }
579
580 void Client::handleCommand_Breath(NetworkPacket* pkt)
581 {
582         LocalPlayer *player = m_env.getLocalPlayer();
583         assert(player != NULL);
584
585         u16 breath;
586
587         *pkt >> breath;
588
589         player->setBreath(breath);
590 }
591
592 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
593 {
594         LocalPlayer *player = m_env.getLocalPlayer();
595         assert(player != NULL);
596
597         v3f pos;
598         f32 pitch, yaw;
599
600         *pkt >> pos >> pitch >> yaw;
601
602         player->setPosition(pos);
603
604         infostream << "Client got TOCLIENT_MOVE_PLAYER"
605                         << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
606                         << " pitch=" << pitch
607                         << " yaw=" << yaw
608                         << std::endl;
609
610         /*
611                 Add to ClientEvent queue.
612                 This has to be sent to the main program because otherwise
613                 it would just force the pitch and yaw values to whatever
614                 the camera points to.
615         */
616         ClientEvent *event = new ClientEvent();
617         event->type = CE_PLAYER_FORCE_MOVE;
618         event->player_force_move.pitch = pitch;
619         event->player_force_move.yaw = yaw;
620         m_client_event_queue.push(event);
621 }
622
623 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
624 {
625         bool set_camera_point_target;
626         v3f camera_point_target;
627
628         *pkt >> set_camera_point_target;
629         *pkt >> camera_point_target;
630
631         ClientEvent *event = new ClientEvent();
632         event->type                                = CE_DEATHSCREEN;
633         event->deathscreen.set_camera_point_target = set_camera_point_target;
634         event->deathscreen.camera_point_target_x   = camera_point_target.X;
635         event->deathscreen.camera_point_target_y   = camera_point_target.Y;
636         event->deathscreen.camera_point_target_z   = camera_point_target.Z;
637         m_client_event_queue.push(event);
638 }
639
640 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
641 {
642         u16 num_files;
643
644         *pkt >> num_files;
645
646         infostream << "Client: Received media announcement: packet size: "
647                         << pkt->getSize() << std::endl;
648
649         if (m_media_downloader == NULL ||
650                         m_media_downloader->isStarted()) {
651                 const char *problem = m_media_downloader ?
652                         "we already saw another announcement" :
653                         "all media has been received already";
654                 errorstream << "Client: Received media announcement but "
655                         << problem << "! "
656                         << " files=" << num_files
657                         << " size=" << pkt->getSize() << std::endl;
658                 return;
659         }
660
661         // Mesh update thread must be stopped while
662         // updating content definitions
663         sanity_check(!m_mesh_update_thread.isRunning());
664
665         for (u16 i = 0; i < num_files; i++) {
666                 std::string name, sha1_base64;
667
668                 *pkt >> name >> sha1_base64;
669
670                 std::string sha1_raw = base64_decode(sha1_base64);
671                 m_media_downloader->addFile(name, sha1_raw);
672         }
673
674         {
675                 std::string str;
676                 *pkt >> str;
677
678                 Strfnd sf(str);
679                 while (!sf.at_end()) {
680                         std::string baseurl = trim(sf.next(","));
681                         if (!baseurl.empty()) {
682                                 m_remote_media_servers.emplace_back(baseurl);
683                                 m_media_downloader->addRemoteServer(baseurl);
684                         }
685                 }
686         }
687
688         m_media_downloader->step(this);
689 }
690
691 void Client::handleCommand_Media(NetworkPacket* pkt)
692 {
693         /*
694                 u16 command
695                 u16 total number of file bunches
696                 u16 index of this bunch
697                 u32 number of files in this bunch
698                 for each file {
699                         u16 length of name
700                         string name
701                         u32 length of data
702                         data
703                 }
704         */
705         u16 num_bunches;
706         u16 bunch_i;
707         u32 num_files;
708
709         *pkt >> num_bunches >> bunch_i >> num_files;
710
711         infostream << "Client: Received files: bunch " << bunch_i << "/"
712                         << num_bunches << " files=" << num_files
713                         << " size=" << pkt->getSize() << std::endl;
714
715         if (num_files == 0)
716                 return;
717
718         bool init_phase = m_media_downloader && m_media_downloader->isStarted();
719
720         if (init_phase) {
721                 // Mesh update thread must be stopped while
722                 // updating content definitions
723                 sanity_check(!m_mesh_update_thread.isRunning());
724         }
725
726         for (u32 i = 0; i < num_files; i++) {
727                 std::string name, data;
728
729                 *pkt >> name;
730                 data = pkt->readLongString();
731
732                 bool ok = false;
733                 if (init_phase) {
734                         ok = m_media_downloader->conventionalTransferDone(name, data, this);
735                 } else {
736                         // Check pending dynamic transfers, one of them must be it
737                         for (const auto &it : m_pending_media_downloads) {
738                                 if (it.second->conventionalTransferDone(name, data, this)) {
739                                         ok = true;
740                                         break;
741                                 }
742                         }
743                 }
744                 if (!ok) {
745                         errorstream << "Client: Received media \"" << name
746                                 << "\" but no downloads pending. " << num_bunches << " bunches, "
747                                 << num_files << " in this one. (init_phase=" << init_phase
748                                 << ")" << std::endl;
749                 }
750         }
751 }
752
753 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
754 {
755         infostream << "Client: Received node definitions: packet size: "
756                         << pkt->getSize() << std::endl;
757
758         // Mesh update thread must be stopped while
759         // updating content definitions
760         sanity_check(!m_mesh_update_thread.isRunning());
761
762         // Decompress node definitions
763         std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
764         std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
765         decompressZlib(tmp_is, tmp_os);
766
767         // Deserialize node definitions
768         m_nodedef->deSerialize(tmp_os);
769         m_nodedef_received = true;
770 }
771
772 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
773 {
774         infostream << "Client: Received item definitions: packet size: "
775                         << pkt->getSize() << std::endl;
776
777         // Mesh update thread must be stopped while
778         // updating content definitions
779         sanity_check(!m_mesh_update_thread.isRunning());
780
781         // Decompress item definitions
782         std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
783         std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
784         decompressZlib(tmp_is, tmp_os);
785
786         // Deserialize node definitions
787         m_itemdef->deSerialize(tmp_os);
788         m_itemdef_received = true;
789 }
790
791 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
792 {
793         /*
794                 [0] u32 server_id
795                 [4] u16 name length
796                 [6] char name[len]
797                 [ 6 + len] f32 gain
798                 [10 + len] u8 type
799                 [11 + len] (f32 * 3) pos
800                 [23 + len] u16 object_id
801                 [25 + len] bool loop
802                 [26 + len] f32 fade
803                 [30 + len] f32 pitch
804                 [34 + len] bool ephemeral
805         */
806
807         s32 server_id;
808         std::string name;
809
810         float gain;
811         u8 type; // 0=local, 1=positional, 2=object
812         v3f pos;
813         u16 object_id;
814         bool loop;
815         float fade = 0.0f;
816         float pitch = 1.0f;
817         bool ephemeral = false;
818
819         *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
820
821         try {
822                 *pkt >> fade;
823                 *pkt >> pitch;
824                 *pkt >> ephemeral;
825         } catch (PacketError &e) {};
826
827         // Start playing
828         int client_id = -1;
829         switch(type) {
830                 case 0: // local
831                         client_id = m_sound->playSound(name, loop, gain, fade, pitch);
832                         break;
833                 case 1: // positional
834                         client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
835                         break;
836                 case 2:
837                 { // object
838                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
839                         if (cao)
840                                 pos = cao->getPosition();
841                         client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
842                         break;
843                 }
844                 default:
845                         break;
846         }
847
848         if (client_id != -1) {
849                 // for ephemeral sounds, server_id is not meaningful
850                 if (!ephemeral) {
851                         m_sounds_server_to_client[server_id] = client_id;
852                         m_sounds_client_to_server[client_id] = server_id;
853                 }
854                 if (object_id != 0)
855                         m_sounds_to_objects[client_id] = object_id;
856         }
857 }
858
859 void Client::handleCommand_StopSound(NetworkPacket* pkt)
860 {
861         s32 server_id;
862
863         *pkt >> server_id;
864
865         std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
866         if (i != m_sounds_server_to_client.end()) {
867                 int client_id = i->second;
868                 m_sound->stopSound(client_id);
869         }
870 }
871
872 void Client::handleCommand_FadeSound(NetworkPacket *pkt)
873 {
874         s32 sound_id;
875         float step;
876         float gain;
877
878         *pkt >> sound_id >> step >> gain;
879
880         std::unordered_map<s32, int>::const_iterator i =
881                         m_sounds_server_to_client.find(sound_id);
882
883         if (i != m_sounds_server_to_client.end())
884                 m_sound->fadeSound(i->second, step, gain);
885 }
886
887 void Client::handleCommand_Privileges(NetworkPacket* pkt)
888 {
889         m_privileges.clear();
890         infostream << "Client: Privileges updated: ";
891         u16 num_privileges;
892
893         *pkt >> num_privileges;
894
895         for (u16 i = 0; i < num_privileges; i++) {
896                 std::string priv;
897
898                 *pkt >> priv;
899
900                 m_privileges.insert(priv);
901                 infostream << priv << " ";
902         }
903         infostream << std::endl;
904 }
905
906 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
907 {
908         LocalPlayer *player = m_env.getLocalPlayer();
909         assert(player != NULL);
910
911         // Store formspec in LocalPlayer
912         player->inventory_formspec = pkt->readLongString();
913 }
914
915 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
916 {
917         std::string name;
918         bool keep_inv = true;
919         *pkt >> name >> keep_inv;
920
921         infostream << "Client: Detached inventory update: \"" << name
922                 << "\", mode=" << (keep_inv ? "update" : "remove") << std::endl;
923
924         const auto &inv_it = m_detached_inventories.find(name);
925         if (!keep_inv) {
926                 if (inv_it != m_detached_inventories.end()) {
927                         delete inv_it->second;
928                         m_detached_inventories.erase(inv_it);
929                 }
930                 return;
931         }
932         Inventory *inv = nullptr;
933         if (inv_it == m_detached_inventories.end()) {
934                 inv = new Inventory(m_itemdef);
935                 m_detached_inventories[name] = inv;
936         } else {
937                 inv = inv_it->second;
938         }
939
940         u16 ignore;
941         *pkt >> ignore; // this used to be the length of the following string, ignore it
942
943         std::string contents(pkt->getRemainingString(), pkt->getRemainingBytes());
944         std::istringstream is(contents, std::ios::binary);
945         inv->deSerialize(is);
946 }
947
948 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
949 {
950         std::string formspec = pkt->readLongString();
951         std::string formname;
952
953         *pkt >> formname;
954
955         ClientEvent *event = new ClientEvent();
956         event->type = CE_SHOW_FORMSPEC;
957         // pointer is required as event is a struct only!
958         // adding a std:string to a struct isn't possible
959         event->show_formspec.formspec = new std::string(formspec);
960         event->show_formspec.formname = new std::string(formname);
961         m_client_event_queue.push(event);
962 }
963
964 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
965 {
966         std::string datastring(pkt->getString(0), pkt->getSize());
967         std::istringstream is(datastring, std::ios_base::binary);
968
969         ParticleParameters p;
970         p.deSerialize(is, m_proto_ver);
971
972         ClientEvent *event = new ClientEvent();
973         event->type           = CE_SPAWN_PARTICLE;
974         event->spawn_particle = new ParticleParameters(p);
975
976         m_client_event_queue.push(event);
977 }
978
979 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
980 {
981         std::string datastring(pkt->getString(0), pkt->getSize());
982         std::istringstream is(datastring, std::ios_base::binary);
983
984         ParticleSpawnerParameters p;
985         u32 server_id;
986         u16 attached_id = 0;
987
988         p.amount             = readU16(is);
989         p.time               = readF32(is);
990         p.minpos             = readV3F32(is);
991         p.maxpos             = readV3F32(is);
992         p.minvel             = readV3F32(is);
993         p.maxvel             = readV3F32(is);
994         p.minacc             = readV3F32(is);
995         p.maxacc             = readV3F32(is);
996         p.minexptime         = readF32(is);
997         p.maxexptime         = readF32(is);
998         p.minsize            = readF32(is);
999         p.maxsize            = readF32(is);
1000         p.collisiondetection = readU8(is);
1001         p.texture            = deSerializeString32(is);
1002
1003         server_id = readU32(is);
1004
1005         p.vertical = readU8(is);
1006         p.collision_removal = readU8(is);
1007
1008         attached_id = readU16(is);
1009
1010         p.animation.deSerialize(is, m_proto_ver);
1011         p.glow = readU8(is);
1012         p.object_collision = readU8(is);
1013
1014         // This is kinda awful
1015         do {
1016                 u16 tmp_param0 = readU16(is);
1017                 if (is.eof())
1018                         break;
1019                 p.node.param0 = tmp_param0;
1020                 p.node.param2 = readU8(is);
1021                 p.node_tile   = readU8(is);
1022         } while (0);
1023
1024         auto event = new ClientEvent();
1025         event->type                            = CE_ADD_PARTICLESPAWNER;
1026         event->add_particlespawner.p           = new ParticleSpawnerParameters(p);
1027         event->add_particlespawner.attached_id = attached_id;
1028         event->add_particlespawner.id          = server_id;
1029
1030         m_client_event_queue.push(event);
1031 }
1032
1033
1034 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
1035 {
1036         u32 server_id;
1037         *pkt >> server_id;
1038
1039         ClientEvent *event = new ClientEvent();
1040         event->type = CE_DELETE_PARTICLESPAWNER;
1041         event->delete_particlespawner.id = server_id;
1042
1043         m_client_event_queue.push(event);
1044 }
1045
1046 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
1047 {
1048         u32 server_id;
1049         u8 type;
1050         v2f pos;
1051         std::string name;
1052         v2f scale;
1053         std::string text;
1054         u32 number;
1055         u32 item;
1056         u32 dir;
1057         v2f align;
1058         v2f offset;
1059         v3f world_pos;
1060         v2s32 size;
1061         s16 z_index = 0;
1062         std::string text2;
1063         u32 style = 0;
1064
1065         *pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item
1066                 >> dir >> align >> offset;
1067         try {
1068                 *pkt >> world_pos;
1069                 *pkt >> size;
1070                 *pkt >> z_index;
1071                 *pkt >> text2;
1072                 *pkt >> style;
1073         } catch(PacketError &e) {};
1074
1075         ClientEvent *event = new ClientEvent();
1076         event->type              = CE_HUDADD;
1077         event->hudadd            = new ClientEventHudAdd();
1078         event->hudadd->server_id = server_id;
1079         event->hudadd->type      = type;
1080         event->hudadd->pos       = pos;
1081         event->hudadd->name      = name;
1082         event->hudadd->scale     = scale;
1083         event->hudadd->text      = text;
1084         event->hudadd->number    = number;
1085         event->hudadd->item      = item;
1086         event->hudadd->dir       = dir;
1087         event->hudadd->align     = align;
1088         event->hudadd->offset    = offset;
1089         event->hudadd->world_pos = world_pos;
1090         event->hudadd->size      = size;
1091         event->hudadd->z_index   = z_index;
1092         event->hudadd->text2     = text2;
1093         event->hudadd->style     = style;
1094         m_client_event_queue.push(event);
1095 }
1096
1097 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1098 {
1099         u32 server_id;
1100
1101         *pkt >> server_id;
1102
1103         ClientEvent *event = new ClientEvent();
1104         event->type     = CE_HUDRM;
1105         event->hudrm.id = server_id;
1106         m_client_event_queue.push(event);
1107 }
1108
1109 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1110 {
1111         std::string sdata;
1112         v2f v2fdata;
1113         v3f v3fdata;
1114         u32 intdata = 0;
1115         v2s32 v2s32data;
1116         u32 server_id;
1117         u8 stat;
1118
1119         *pkt >> server_id >> stat;
1120
1121         // Keep in sync with:server.cpp -> SendHUDChange
1122         switch ((HudElementStat)stat) {
1123                 case HUD_STAT_POS:
1124                 case HUD_STAT_SCALE:
1125                 case HUD_STAT_ALIGN:
1126                 case HUD_STAT_OFFSET:
1127                         *pkt >> v2fdata;
1128                         break;
1129                 case HUD_STAT_NAME:
1130                 case HUD_STAT_TEXT:
1131                 case HUD_STAT_TEXT2:
1132                         *pkt >> sdata;
1133                         break;
1134                 case HUD_STAT_WORLD_POS:
1135                         *pkt >> v3fdata;
1136                         break;
1137                 case HUD_STAT_SIZE:
1138                         *pkt >> v2s32data;
1139                         break;
1140                 default:
1141                         *pkt >> intdata;
1142                         break;
1143         }
1144
1145         ClientEvent *event = new ClientEvent();
1146         event->type                 = CE_HUDCHANGE;
1147         event->hudchange            = new ClientEventHudChange();
1148         event->hudchange->id        = server_id;
1149         event->hudchange->stat      = static_cast<HudElementStat>(stat);
1150         event->hudchange->v2fdata   = v2fdata;
1151         event->hudchange->v3fdata   = v3fdata;
1152         event->hudchange->sdata     = sdata;
1153         event->hudchange->data      = intdata;
1154         event->hudchange->v2s32data = v2s32data;
1155         m_client_event_queue.push(event);
1156 }
1157
1158 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1159 {
1160         u32 flags, mask;
1161
1162         *pkt >> flags >> mask;
1163
1164         LocalPlayer *player = m_env.getLocalPlayer();
1165         assert(player != NULL);
1166
1167         bool was_minimap_visible = player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE;
1168         bool was_minimap_radar_visible = player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE;
1169
1170         player->hud_flags &= ~mask;
1171         player->hud_flags |= flags;
1172
1173         m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1174         bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1175
1176         // Not so satisying code to keep compatibility with old fixed mode system
1177         // -->
1178
1179         // Hide minimap if it has been disabled by the server
1180         if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible)
1181                 // defers a minimap update, therefore only call it if really
1182                 // needed, by checking that minimap was visible before
1183                 m_minimap->setModeIndex(0);
1184
1185         // If radar has been disabled, try to find a non radar mode or fall back to 0
1186         if (m_minimap && m_minimap_radar_disabled_by_server
1187                         && was_minimap_radar_visible) {
1188                 while (m_minimap->getModeIndex() > 0 &&
1189                                 m_minimap->getModeDef().type == MINIMAP_TYPE_RADAR)
1190                         m_minimap->nextMode();
1191         }
1192         // <--
1193         // End of 'not so satifying code'
1194 }
1195
1196 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1197 {
1198         u16 param; std::string value;
1199
1200         *pkt >> param >> value;
1201
1202         LocalPlayer *player = m_env.getLocalPlayer();
1203         assert(player != NULL);
1204
1205         if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1206                 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1207                 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1208                         player->hud_hotbar_itemcount = hotbar_itemcount;
1209         }
1210         else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1211                 player->hotbar_image = value;
1212         }
1213         else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1214                 player->hotbar_selected_image = value;
1215         }
1216 }
1217
1218 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1219 {
1220         if (m_proto_ver < 39) {
1221                 // Handle Protocol 38 and below servers with old set_sky,
1222                 // ensuring the classic look is kept.
1223                 std::string datastring(pkt->getString(0), pkt->getSize());
1224                 std::istringstream is(datastring, std::ios_base::binary);
1225
1226                 SkyboxParams skybox;
1227                 skybox.bgcolor = video::SColor(readARGB8(is));
1228                 skybox.type = std::string(deSerializeString16(is));
1229                 u16 count = readU16(is);
1230
1231                 for (size_t i = 0; i < count; i++)
1232                         skybox.textures.emplace_back(deSerializeString16(is));
1233
1234                 skybox.clouds = true;
1235                 try {
1236                         skybox.clouds = readU8(is);
1237                 } catch (...) {}
1238
1239                 // Use default skybox settings:
1240                 SunParams sun = SkyboxDefaults::getSunDefaults();
1241                 MoonParams moon = SkyboxDefaults::getMoonDefaults();
1242                 StarParams stars = SkyboxDefaults::getStarDefaults();
1243
1244                 // Fix for "regular" skies, as color isn't kept:
1245                 if (skybox.type == "regular") {
1246                         skybox.sky_color = SkyboxDefaults::getSkyColorDefaults();
1247                         skybox.fog_tint_type = "default";
1248                         skybox.fog_moon_tint = video::SColor(255, 255, 255, 255);
1249                         skybox.fog_sun_tint = video::SColor(255, 255, 255, 255);
1250                 } else {
1251                         sun.visible = false;
1252                         sun.sunrise_visible = false;
1253                         moon.visible = false;
1254                         stars.visible = false;
1255                 }
1256
1257                 // Skybox, sun, moon and stars ClientEvents:
1258                 ClientEvent *sky_event = new ClientEvent();
1259                 sky_event->type = CE_SET_SKY;
1260                 sky_event->set_sky = new SkyboxParams(skybox);
1261                 m_client_event_queue.push(sky_event);
1262
1263                 ClientEvent *sun_event = new ClientEvent();
1264                 sun_event->type = CE_SET_SUN;
1265                 sun_event->sun_params = new SunParams(sun);
1266                 m_client_event_queue.push(sun_event);
1267
1268                 ClientEvent *moon_event = new ClientEvent();
1269                 moon_event->type = CE_SET_MOON;
1270                 moon_event->moon_params = new MoonParams(moon);
1271                 m_client_event_queue.push(moon_event);
1272
1273                 ClientEvent *star_event = new ClientEvent();
1274                 star_event->type = CE_SET_STARS;
1275                 star_event->star_params = new StarParams(stars);
1276                 m_client_event_queue.push(star_event);
1277         } else {
1278                 SkyboxParams skybox;
1279                 u16 texture_count;
1280                 std::string texture;
1281
1282                 *pkt >> skybox.bgcolor >> skybox.type >> skybox.clouds >>
1283                         skybox.fog_sun_tint >> skybox.fog_moon_tint >> skybox.fog_tint_type;
1284
1285                 if (skybox.type == "skybox") {
1286                         *pkt >> texture_count;
1287                         for (int i = 0; i < texture_count; i++) {
1288                                 *pkt >> texture;
1289                                 skybox.textures.emplace_back(texture);
1290                         }
1291                 }
1292                 else if (skybox.type == "regular") {
1293                         *pkt >> skybox.sky_color.day_sky >> skybox.sky_color.day_horizon
1294                                 >> skybox.sky_color.dawn_sky >> skybox.sky_color.dawn_horizon
1295                                 >> skybox.sky_color.night_sky >> skybox.sky_color.night_horizon
1296                                 >> skybox.sky_color.indoors;
1297                 }
1298
1299                 ClientEvent *event = new ClientEvent();
1300                 event->type = CE_SET_SKY;
1301                 event->set_sky = new SkyboxParams(skybox);
1302                 m_client_event_queue.push(event);
1303         }
1304 }
1305
1306 void Client::handleCommand_HudSetSun(NetworkPacket *pkt)
1307 {
1308         SunParams sun;
1309
1310         *pkt >> sun.visible >> sun.texture>> sun.tonemap
1311                 >> sun.sunrise >> sun.sunrise_visible >> sun.scale;
1312
1313         ClientEvent *event = new ClientEvent();
1314         event->type        = CE_SET_SUN;
1315         event->sun_params  = new SunParams(sun);
1316         m_client_event_queue.push(event);
1317 }
1318
1319 void Client::handleCommand_HudSetMoon(NetworkPacket *pkt)
1320 {
1321         MoonParams moon;
1322
1323         *pkt >> moon.visible >> moon.texture
1324                 >> moon.tonemap >> moon.scale;
1325
1326         ClientEvent *event = new ClientEvent();
1327         event->type        = CE_SET_MOON;
1328         event->moon_params = new MoonParams(moon);
1329         m_client_event_queue.push(event);
1330 }
1331
1332 void Client::handleCommand_HudSetStars(NetworkPacket *pkt)
1333 {
1334         StarParams stars;
1335
1336         *pkt >> stars.visible >> stars.count
1337                 >> stars.starcolor >> stars.scale;
1338
1339         ClientEvent *event = new ClientEvent();
1340         event->type        = CE_SET_STARS;
1341         event->star_params = new StarParams(stars);
1342
1343         m_client_event_queue.push(event);
1344 }
1345
1346 void Client::handleCommand_CloudParams(NetworkPacket* pkt)
1347 {
1348         f32 density;
1349         video::SColor color_bright;
1350         video::SColor color_ambient;
1351         f32 height;
1352         f32 thickness;
1353         v2f speed;
1354
1355         *pkt >> density >> color_bright >> color_ambient
1356                         >> height >> thickness >> speed;
1357
1358         ClientEvent *event = new ClientEvent();
1359         event->type                       = CE_CLOUD_PARAMS;
1360         event->cloud_params.density       = density;
1361         // use the underlying u32 representation, because we can't
1362         // use struct members with constructors here, and this way
1363         // we avoid using new() and delete() for no good reason
1364         event->cloud_params.color_bright  = color_bright.color;
1365         event->cloud_params.color_ambient = color_ambient.color;
1366         event->cloud_params.height        = height;
1367         event->cloud_params.thickness     = thickness;
1368         // same here: deconstruct to skip constructor
1369         event->cloud_params.speed_x       = speed.X;
1370         event->cloud_params.speed_y       = speed.Y;
1371         m_client_event_queue.push(event);
1372 }
1373
1374 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1375 {
1376         bool do_override;
1377         u16 day_night_ratio_u;
1378
1379         *pkt >> do_override >> day_night_ratio_u;
1380
1381         float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1382
1383         ClientEvent *event = new ClientEvent();
1384         event->type                                 = CE_OVERRIDE_DAY_NIGHT_RATIO;
1385         event->override_day_night_ratio.do_override = do_override;
1386         event->override_day_night_ratio.ratio_f     = day_night_ratio_f;
1387         m_client_event_queue.push(event);
1388 }
1389
1390 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1391 {
1392         LocalPlayer *player = m_env.getLocalPlayer();
1393         assert(player != NULL);
1394
1395         *pkt >> player->local_animations[0];
1396         *pkt >> player->local_animations[1];
1397         *pkt >> player->local_animations[2];
1398         *pkt >> player->local_animations[3];
1399         *pkt >> player->local_animation_speed;
1400
1401         player->last_animation = -1;
1402 }
1403
1404 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1405 {
1406         LocalPlayer *player = m_env.getLocalPlayer();
1407         assert(player != NULL);
1408
1409         *pkt >> player->eye_offset_first >> player->eye_offset_third;
1410 }
1411
1412 void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt)
1413 {
1414         u8 type;
1415         u16 num_players;
1416         *pkt >> type >> num_players;
1417         PlayerListModifer notice_type = (PlayerListModifer) type;
1418
1419         for (u16 i = 0; i < num_players; i++) {
1420                 std::string name;
1421                 *pkt >> name;
1422                 switch (notice_type) {
1423                 case PLAYER_LIST_INIT:
1424                 case PLAYER_LIST_ADD:
1425                         m_env.addPlayerName(name);
1426                         continue;
1427                 case PLAYER_LIST_REMOVE:
1428                         m_env.removePlayerName(name);
1429                         continue;
1430                 }
1431         }
1432 }
1433
1434 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1435 {
1436         if (m_chosen_auth_mech != AUTH_MECHANISM_SRP &&
1437                         m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
1438                 errorstream << "Client: Received SRP S_B login message,"
1439                         << " but wasn't supposed to (chosen_mech="
1440                         << m_chosen_auth_mech << ")." << std::endl;
1441                 return;
1442         }
1443
1444         char *bytes_M = 0;
1445         size_t len_M = 0;
1446         SRPUser *usr = (SRPUser *) m_auth_data;
1447         std::string s;
1448         std::string B;
1449         *pkt >> s >> B;
1450
1451         infostream << "Client: Received TOCLIENT_SRP_BYTES_S_B." << std::endl;
1452
1453         srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1454                 (const unsigned char *) B.c_str(), B.size(),
1455                 (unsigned char **) &bytes_M, &len_M);
1456
1457         if ( !bytes_M ) {
1458                 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1459                 return;
1460         }
1461
1462         NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1463         resp_pkt << std::string(bytes_M, len_M);
1464         Send(&resp_pkt);
1465 }
1466
1467 void Client::handleCommand_FormspecPrepend(NetworkPacket *pkt)
1468 {
1469         LocalPlayer *player = m_env.getLocalPlayer();
1470         assert(player != NULL);
1471
1472         // Store formspec in LocalPlayer
1473         *pkt >> player->formspec_prepend;
1474 }
1475
1476 void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
1477 {
1478         *pkt >> m_csm_restriction_flags >> m_csm_restriction_noderange;
1479
1480         // Restrictions were received -> load mods if it's enabled
1481         // Note: this should be moved after mods receptions from server instead
1482         loadMods();
1483 }
1484
1485 void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
1486 {
1487         v3f added_vel;
1488
1489         *pkt >> added_vel;
1490
1491         LocalPlayer *player = m_env.getLocalPlayer();
1492         assert(player != NULL);
1493         player->addVelocity(added_vel);
1494 }
1495
1496 void Client::handleCommand_MediaPush(NetworkPacket *pkt)
1497 {
1498         std::string raw_hash, filename, filedata;
1499         u32 token;
1500         bool cached;
1501
1502         *pkt >> raw_hash >> filename >> cached;
1503         if (m_proto_ver >= 40)
1504                 *pkt >> token;
1505         else
1506                 filedata = pkt->readLongString();
1507
1508         if (raw_hash.size() != 20 || filename.empty() ||
1509                         (m_proto_ver < 40 && filedata.empty()) ||
1510                         !string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
1511                 throw PacketError("Illegal filename, data or hash");
1512         }
1513
1514         verbosestream << "Server pushes media file \"" << filename << "\" ";
1515         if (filedata.empty())
1516                 verbosestream << "to be fetched ";
1517         else
1518                 verbosestream << "with " << filedata.size() << " bytes ";
1519         verbosestream << "(cached=" << cached << ")" << std::endl;
1520
1521         if (m_media_pushed_files.count(filename) != 0) {
1522                 // Ignore (but acknowledge). Previously this was for sync purposes,
1523                 // but even in new versions media cannot be replaced at runtime.
1524                 if (m_proto_ver >= 40)
1525                         sendHaveMedia({ token });
1526                 return;
1527         }
1528
1529         if (!filedata.empty()) {
1530                 // LEGACY CODEPATH
1531                 // Compute and check checksum of data
1532                 std::string computed_hash;
1533                 {
1534                         SHA1 ctx;
1535                         ctx.addBytes(filedata.c_str(), filedata.size());
1536                         unsigned char *buf = ctx.getDigest();
1537                         computed_hash.assign((char*) buf, 20);
1538                         free(buf);
1539                 }
1540                 if (raw_hash != computed_hash) {
1541                         verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
1542                         return;
1543                 }
1544
1545                 // Actually load media
1546                 loadMedia(filedata, filename, true);
1547                 m_media_pushed_files.insert(filename);
1548
1549                 // Cache file for the next time when this client joins the same server
1550                 if (cached)
1551                         clientMediaUpdateCache(raw_hash, filedata);
1552                 return;
1553         }
1554
1555         m_media_pushed_files.insert(filename);
1556
1557         // create a downloader for this file
1558         auto downloader(std::make_shared<SingleMediaDownloader>(cached));
1559         m_pending_media_downloads.emplace_back(token, downloader);
1560         downloader->addFile(filename, raw_hash);
1561         for (const auto &baseurl : m_remote_media_servers)
1562                 downloader->addRemoteServer(baseurl);
1563
1564         downloader->step(this);
1565 }
1566
1567 /*
1568  * Mod channels
1569  */
1570
1571 void Client::handleCommand_ModChannelMsg(NetworkPacket *pkt)
1572 {
1573         std::string channel_name, sender, channel_msg;
1574         *pkt >> channel_name >> sender >> channel_msg;
1575
1576         verbosestream << "Mod channel message received from server " << pkt->getPeerId()
1577                 << " on channel " << channel_name << ". sender: `" << sender << "`, message: "
1578                 << channel_msg << std::endl;
1579
1580         if (!m_modchannel_mgr->channelRegistered(channel_name)) {
1581                 verbosestream << "Server sent us messages on unregistered channel "
1582                         << channel_name << ", ignoring." << std::endl;
1583                 return;
1584         }
1585
1586         m_script->on_modchannel_message(channel_name, sender, channel_msg);
1587 }
1588
1589 void Client::handleCommand_ModChannelSignal(NetworkPacket *pkt)
1590 {
1591         u8 signal_tmp;
1592         ModChannelSignal signal;
1593         std::string channel;
1594
1595         *pkt >> signal_tmp >> channel;
1596
1597         signal = (ModChannelSignal)signal_tmp;
1598
1599         bool valid_signal = true;
1600         // @TODO: send Signal to Lua API
1601         switch (signal) {
1602                 case MODCHANNEL_SIGNAL_JOIN_OK:
1603                         m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
1604                         infostream << "Server ack our mod channel join on channel `" << channel
1605                                 << "`, joining." << std::endl;
1606                         break;
1607                 case MODCHANNEL_SIGNAL_JOIN_FAILURE:
1608                         // Unable to join, remove channel
1609                         m_modchannel_mgr->leaveChannel(channel, 0);
1610                         infostream << "Server refused our mod channel join on channel `" << channel
1611                                 << "`" << std::endl;
1612                         break;
1613                 case MODCHANNEL_SIGNAL_LEAVE_OK:
1614 #ifndef NDEBUG
1615                         infostream << "Server ack our mod channel leave on channel " << channel
1616                                 << "`, leaving." << std::endl;
1617 #endif
1618                         break;
1619                 case MODCHANNEL_SIGNAL_LEAVE_FAILURE:
1620                         infostream << "Server refused our mod channel leave on channel `" << channel
1621                                 << "`" << std::endl;
1622                         break;
1623                 case MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED:
1624 #ifndef NDEBUG
1625                         // Generally unused, but ensure we don't do an implementation error
1626                         infostream << "Server tells us we sent a message on channel `" << channel
1627                                 << "` but we are not registered. Message was dropped." << std::endl;
1628 #endif
1629                         break;
1630                 case MODCHANNEL_SIGNAL_SET_STATE: {
1631                         u8 state;
1632                         *pkt >> state;
1633
1634                         if (state == MODCHANNEL_STATE_INIT || state >= MODCHANNEL_STATE_MAX) {
1635                                 infostream << "Received wrong channel state " << state
1636                                                 << ", ignoring." << std::endl;
1637                                 return;
1638                         }
1639
1640                         m_modchannel_mgr->setChannelState(channel, (ModChannelState) state);
1641                         infostream << "Server sets mod channel `" << channel
1642                                         << "` in read-only mode." << std::endl;
1643                         break;
1644                 }
1645                 default:
1646 #ifndef NDEBUG
1647                         warningstream << "Received unhandled mod channel signal ID "
1648                                 << signal << ", ignoring." << std::endl;
1649 #endif
1650                         valid_signal = false;
1651                         break;
1652         }
1653
1654         // If signal is valid, forward it to client side mods
1655         if (valid_signal)
1656                 m_script->on_modchannel_signal(channel, signal);
1657 }
1658
1659 void Client::handleCommand_MinimapModes(NetworkPacket *pkt)
1660 {
1661         u16 count; // modes
1662         u16 mode;  // wanted current mode index after change
1663
1664         *pkt >> count >> mode;
1665
1666         if (m_minimap)
1667                 m_minimap->clearModes();
1668
1669         for (size_t index = 0; index < count; index++) {
1670                 u16 type;
1671                 std::string label;
1672                 u16 size;
1673                 std::string texture;
1674                 u16 scale;
1675
1676                 *pkt >> type >> label >> size >> texture >> scale;
1677
1678                 if (m_minimap)
1679                         m_minimap->addMode(MinimapType(type), size, label, texture, scale);
1680         }
1681
1682         if (m_minimap)
1683                 m_minimap->setModeIndex(mode);
1684 }