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