]> git.lizzy.rs Git - minetest.git/blob - src/network/clientpackethandler.cpp
Translated using Weblate (Chinese (Simplified))
[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
47 void Client::handleCommand_Deprecated(NetworkPacket* pkt)
48 {
49         infostream << "Got deprecated command "
50                         << toClientCommandTable[pkt->getCommand()].name << " from peer "
51                         << pkt->getPeerId() << "!" << std::endl;
52 }
53
54 void Client::handleCommand_Hello(NetworkPacket* pkt)
55 {
56         if (pkt->getSize() < 1)
57                 return;
58
59         u8 serialization_ver;
60         u16 proto_ver;
61         u16 compression_mode;
62         u32 auth_mechs;
63         std::string username_legacy; // for case insensitivity
64         *pkt >> serialization_ver >> compression_mode >> proto_ver
65                 >> auth_mechs >> username_legacy;
66
67         // Chose an auth method we support
68         AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);
69
70         infostream << "Client: TOCLIENT_HELLO received with "
71                         << "serialization_ver=" << (u32)serialization_ver
72                         << ", auth_mechs=" << auth_mechs
73                         << ", proto_ver=" << proto_ver
74                         << ", compression_mode=" << compression_mode
75                         << ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
76
77         if (!ser_ver_supported(serialization_ver)) {
78                 infostream << "Client: TOCLIENT_HELLO: Server sent "
79                                 << "unsupported ser_fmt_ver"<< std::endl;
80                 return;
81         }
82
83         m_server_ser_ver = serialization_ver;
84         m_proto_ver = proto_ver;
85
86         //TODO verify that username_legacy matches sent username, only
87         // differs in casing (make both uppercase and compare)
88         // This is only neccessary though when we actually want to add casing support
89
90         if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
91                 // we recieved a TOCLIENT_HELLO while auth was already going on
92                 errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
93                         << "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
94                 if (m_chosen_auth_mech == AUTH_MECHANISM_SRP ||
95                                 m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD) {
96                         srp_user_delete((SRPUser *) m_auth_data);
97                         m_auth_data = 0;
98                 }
99         }
100
101         // Authenticate using that method, or abort if there wasn't any method found
102         if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
103                 if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP &&
104                                 !m_simple_singleplayer_mode &&
105                                 !getServerAddress().isLocalhost() &&
106                                 g_settings->getBool("enable_register_confirmation")) {
107                         promptConfirmRegistration(chosen_auth_mechanism);
108                 } else {
109                         startAuth(chosen_auth_mechanism);
110                 }
111         } else {
112                 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
113                 m_access_denied = true;
114                 m_access_denied_reason = "Unknown";
115                 m_con->Disconnect();
116         }
117
118 }
119
120 void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
121 {
122         deleteAuthData();
123
124         v3f playerpos;
125         *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
126                 >> m_sudo_auth_methods;
127
128         playerpos -= v3f(0, BS / 2, 0);
129
130         // Set player position
131         LocalPlayer *player = m_env.getLocalPlayer();
132         assert(player != NULL);
133         player->setPosition(playerpos);
134
135         infostream << "Client: received map seed: " << m_map_seed << std::endl;
136         infostream << "Client: received recommended send interval "
137                                         << m_recommended_send_interval<<std::endl;
138
139         // Reply to server
140         /*~ DO NOT TRANSLATE THIS LITERALLY!
141         This is a special string which needs to contain the translation's
142         language code (e.g. "de" for German). */
143         std::string lang = gettext("LANG_CODE");
144         if (lang == "LANG_CODE")
145                 lang = "";
146
147         NetworkPacket resp_pkt(TOSERVER_INIT2, sizeof(u16) + lang.size());
148         resp_pkt << lang;
149         Send(&resp_pkt);
150
151         m_state = LC_Init;
152 }
153 void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
154 {
155         deleteAuthData();
156
157         m_password = m_new_password;
158
159         verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
160
161         // send packet to actually set the password
162         startAuth(AUTH_MECHANISM_FIRST_SRP);
163
164         // reset again
165         m_chosen_auth_mech = AUTH_MECHANISM_NONE;
166 }
167 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
168 {
169         ChatMessage *chatMessage = new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
170                         L"Password change denied. Password NOT changed.");
171         pushToChatQueue(chatMessage);
172         // reset everything and be sad
173         deleteAuthData();
174 }
175
176 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
177 {
178         // The server didn't like our password. Note, this needs
179         // to be processed even if the serialisation format has
180         // not been agreed yet, the same as TOCLIENT_INIT.
181         m_access_denied = true;
182         m_access_denied_reason = "Unknown";
183
184         if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) {
185                 // 13/03/15 Legacy code from 0.4.12 and lesser but is still used
186                 // in some places of the server code
187                 if (pkt->getSize() >= 2) {
188                         std::wstring wide_reason;
189                         *pkt >> wide_reason;
190                         m_access_denied_reason = wide_to_utf8(wide_reason);
191                 }
192                 return;
193         }
194
195         if (pkt->getSize() < 1)
196                 return;
197
198         u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
199         *pkt >> denyCode;
200         if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN ||
201                         denyCode == SERVER_ACCESSDENIED_CRASH) {
202                 *pkt >> m_access_denied_reason;
203                 if (m_access_denied_reason.empty()) {
204                         m_access_denied_reason = accessDeniedStrings[denyCode];
205                 }
206                 u8 reconnect;
207                 *pkt >> reconnect;
208                 m_access_denied_reconnect = reconnect & 1;
209         } else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
210                 *pkt >> m_access_denied_reason;
211         } else if (denyCode == SERVER_ACCESSDENIED_TOO_MANY_USERS) {
212                 m_access_denied_reason = accessDeniedStrings[denyCode];
213                 m_access_denied_reconnect = true;
214         } else if (denyCode < SERVER_ACCESSDENIED_MAX) {
215                 m_access_denied_reason = accessDeniedStrings[denyCode];
216         } else {
217                 // Allow us to add new error messages to the
218                 // protocol without raising the protocol version, if we want to.
219                 // Until then (which may be never), this is outside
220                 // of the defined protocol.
221                 *pkt >> m_access_denied_reason;
222                 if (m_access_denied_reason.empty()) {
223                         m_access_denied_reason = "Unknown";
224                 }
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;
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         try {
674                 std::string str;
675
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_media_downloader->addRemoteServer(baseurl);
683                 }
684         }
685         catch(SerializationError& e) {
686                 // not supported by server or turned off
687         }
688
689         m_media_downloader->step(this);
690 }
691
692 void Client::handleCommand_Media(NetworkPacket* pkt)
693 {
694         /*
695                 u16 command
696                 u16 total number of file bunches
697                 u16 index of this bunch
698                 u32 number of files in this bunch
699                 for each file {
700                         u16 length of name
701                         string name
702                         u32 length of data
703                         data
704                 }
705         */
706         u16 num_bunches;
707         u16 bunch_i;
708         u32 num_files;
709
710         *pkt >> num_bunches >> bunch_i >> num_files;
711
712         infostream << "Client: Received files: bunch " << bunch_i << "/"
713                         << num_bunches << " files=" << num_files
714                         << " size=" << pkt->getSize() << std::endl;
715
716         if (num_files == 0)
717                 return;
718
719         if (!m_media_downloader || !m_media_downloader->isStarted()) {
720                 const char *problem = m_media_downloader ?
721                         "media has not been requested" :
722                         "all media has been received already";
723                 errorstream << "Client: Received media but "
724                         << problem << "! "
725                         << " bunch " << bunch_i << "/" << num_bunches
726                         << " files=" << num_files
727                         << " size=" << pkt->getSize() << std::endl;
728                 return;
729         }
730
731         // Mesh update thread must be stopped while
732         // updating content definitions
733         sanity_check(!m_mesh_update_thread.isRunning());
734
735         for (u32 i=0; i < num_files; i++) {
736                 std::string name;
737
738                 *pkt >> name;
739
740                 std::string data = pkt->readLongString();
741
742                 m_media_downloader->conventionalTransferDone(
743                                 name, data, this);
744         }
745 }
746
747 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
748 {
749         infostream << "Client: Received node definitions: packet size: "
750                         << pkt->getSize() << std::endl;
751
752         // Mesh update thread must be stopped while
753         // updating content definitions
754         sanity_check(!m_mesh_update_thread.isRunning());
755
756         // Decompress node definitions
757         std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
758         std::ostringstream tmp_os;
759         decompressZlib(tmp_is, tmp_os);
760
761         // Deserialize node definitions
762         std::istringstream tmp_is2(tmp_os.str());
763         m_nodedef->deSerialize(tmp_is2);
764         m_nodedef_received = true;
765 }
766
767 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
768 {
769         infostream << "Client: Received item definitions: packet size: "
770                         << pkt->getSize() << std::endl;
771
772         // Mesh update thread must be stopped while
773         // updating content definitions
774         sanity_check(!m_mesh_update_thread.isRunning());
775
776         // Decompress item definitions
777         std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
778         std::ostringstream tmp_os;
779         decompressZlib(tmp_is, tmp_os);
780
781         // Deserialize node definitions
782         std::istringstream tmp_is2(tmp_os.str());
783         m_itemdef->deSerialize(tmp_is2);
784         m_itemdef_received = true;
785 }
786
787 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
788 {
789         /*
790                 [0] u32 server_id
791                 [4] u16 name length
792                 [6] char name[len]
793                 [ 6 + len] f32 gain
794                 [10 + len] u8 type
795                 [11 + len] (f32 * 3) pos
796                 [23 + len] u16 object_id
797                 [25 + len] bool loop
798                 [26 + len] f32 fade
799                 [30 + len] f32 pitch
800                 [34 + len] bool ephemeral
801         */
802
803         s32 server_id;
804         std::string name;
805
806         float gain;
807         u8 type; // 0=local, 1=positional, 2=object
808         v3f pos;
809         u16 object_id;
810         bool loop;
811         float fade = 0.0f;
812         float pitch = 1.0f;
813         bool ephemeral = false;
814
815         *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
816
817         try {
818                 *pkt >> fade;
819                 *pkt >> pitch;
820                 *pkt >> ephemeral;
821         } catch (PacketError &e) {};
822
823         // Start playing
824         int client_id = -1;
825         switch(type) {
826                 case 0: // local
827                         client_id = m_sound->playSound(name, loop, gain, fade, pitch);
828                         break;
829                 case 1: // positional
830                         client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
831                         break;
832                 case 2:
833                 { // object
834                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
835                         if (cao)
836                                 pos = cao->getPosition();
837                         client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
838                         break;
839                 }
840                 default:
841                         break;
842         }
843
844         if (client_id != -1) {
845                 // for ephemeral sounds, server_id is not meaningful
846                 if (!ephemeral) {
847                         m_sounds_server_to_client[server_id] = client_id;
848                         m_sounds_client_to_server[client_id] = server_id;
849                 }
850                 if (object_id != 0)
851                         m_sounds_to_objects[client_id] = object_id;
852         }
853 }
854
855 void Client::handleCommand_StopSound(NetworkPacket* pkt)
856 {
857         s32 server_id;
858
859         *pkt >> server_id;
860
861         std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
862         if (i != m_sounds_server_to_client.end()) {
863                 int client_id = i->second;
864                 m_sound->stopSound(client_id);
865         }
866 }
867
868 void Client::handleCommand_FadeSound(NetworkPacket *pkt)
869 {
870         s32 sound_id;
871         float step;
872         float gain;
873
874         *pkt >> sound_id >> step >> gain;
875
876         std::unordered_map<s32, int>::const_iterator i =
877                         m_sounds_server_to_client.find(sound_id);
878
879         if (i != m_sounds_server_to_client.end())
880                 m_sound->fadeSound(i->second, step, gain);
881 }
882
883 void Client::handleCommand_Privileges(NetworkPacket* pkt)
884 {
885         m_privileges.clear();
886         infostream << "Client: Privileges updated: ";
887         u16 num_privileges;
888
889         *pkt >> num_privileges;
890
891         for (u16 i = 0; i < num_privileges; i++) {
892                 std::string priv;
893
894                 *pkt >> priv;
895
896                 m_privileges.insert(priv);
897                 infostream << priv << " ";
898         }
899         infostream << std::endl;
900 }
901
902 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
903 {
904         LocalPlayer *player = m_env.getLocalPlayer();
905         assert(player != NULL);
906
907         // Store formspec in LocalPlayer
908         player->inventory_formspec = pkt->readLongString();
909 }
910
911 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
912 {
913         std::string name;
914         bool keep_inv = true;
915         *pkt >> name >> keep_inv;
916
917         infostream << "Client: Detached inventory update: \"" << name
918                 << "\", mode=" << (keep_inv ? "update" : "remove") << std::endl;
919
920         const auto &inv_it = m_detached_inventories.find(name);
921         if (!keep_inv) {
922                 if (inv_it != m_detached_inventories.end()) {
923                         delete inv_it->second;
924                         m_detached_inventories.erase(inv_it);
925                 }
926                 return;
927         }
928         Inventory *inv = nullptr;
929         if (inv_it == m_detached_inventories.end()) {
930                 inv = new Inventory(m_itemdef);
931                 m_detached_inventories[name] = inv;
932         } else {
933                 inv = inv_it->second;
934         }
935
936         u16 ignore;
937         *pkt >> ignore; // this used to be the length of the following string, ignore it
938
939         std::string contents(pkt->getRemainingString(), pkt->getRemainingBytes());
940         std::istringstream is(contents, std::ios::binary);
941         inv->deSerialize(is);
942 }
943
944 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
945 {
946         std::string formspec = pkt->readLongString();
947         std::string formname;
948
949         *pkt >> formname;
950
951         ClientEvent *event = new ClientEvent();
952         event->type = CE_SHOW_FORMSPEC;
953         // pointer is required as event is a struct only!
954         // adding a std:string to a struct isn't possible
955         event->show_formspec.formspec = new std::string(formspec);
956         event->show_formspec.formname = new std::string(formname);
957         m_client_event_queue.push(event);
958 }
959
960 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
961 {
962         std::string datastring(pkt->getString(0), pkt->getSize());
963         std::istringstream is(datastring, std::ios_base::binary);
964
965         ParticleParameters p;
966         p.deSerialize(is, m_proto_ver);
967
968         ClientEvent *event = new ClientEvent();
969         event->type           = CE_SPAWN_PARTICLE;
970         event->spawn_particle = new ParticleParameters(p);
971
972         m_client_event_queue.push(event);
973 }
974
975 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
976 {
977         std::string datastring(pkt->getString(0), pkt->getSize());
978         std::istringstream is(datastring, std::ios_base::binary);
979
980         ParticleSpawnerParameters p;
981         u32 server_id;
982         u16 attached_id = 0;
983
984         p.amount             = readU16(is);
985         p.time               = readF32(is);
986         p.minpos             = readV3F32(is);
987         p.maxpos             = readV3F32(is);
988         p.minvel             = readV3F32(is);
989         p.maxvel             = readV3F32(is);
990         p.minacc             = readV3F32(is);
991         p.maxacc             = readV3F32(is);
992         p.minexptime         = readF32(is);
993         p.maxexptime         = readF32(is);
994         p.minsize            = readF32(is);
995         p.maxsize            = readF32(is);
996         p.collisiondetection = readU8(is);
997         p.texture            = deSerializeString32(is);
998
999         server_id = readU32(is);
1000
1001         p.vertical = readU8(is);
1002         p.collision_removal = readU8(is);
1003
1004         attached_id = readU16(is);
1005
1006         p.animation.deSerialize(is, m_proto_ver);
1007         p.glow = readU8(is);
1008         p.object_collision = readU8(is);
1009
1010         // This is kinda awful
1011         do {
1012                 u16 tmp_param0 = readU16(is);
1013                 if (is.eof())
1014                         break;
1015                 p.node.param0 = tmp_param0;
1016                 p.node.param2 = readU8(is);
1017                 p.node_tile   = readU8(is);
1018         } while (0);
1019
1020         auto event = new ClientEvent();
1021         event->type                            = CE_ADD_PARTICLESPAWNER;
1022         event->add_particlespawner.p           = new ParticleSpawnerParameters(p);
1023         event->add_particlespawner.attached_id = attached_id;
1024         event->add_particlespawner.id          = server_id;
1025
1026         m_client_event_queue.push(event);
1027 }
1028
1029
1030 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
1031 {
1032         u32 server_id;
1033         *pkt >> server_id;
1034
1035         ClientEvent *event = new ClientEvent();
1036         event->type = CE_DELETE_PARTICLESPAWNER;
1037         event->delete_particlespawner.id = server_id;
1038
1039         m_client_event_queue.push(event);
1040 }
1041
1042 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
1043 {
1044         std::string datastring(pkt->getString(0), pkt->getSize());
1045         std::istringstream is(datastring, std::ios_base::binary);
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
1063         *pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item
1064                 >> dir >> align >> offset;
1065         try {
1066                 *pkt >> world_pos;
1067                 *pkt >> size;
1068                 *pkt >> z_index;
1069                 *pkt >> text2;
1070         } catch(PacketError &e) {};
1071
1072         ClientEvent *event = new ClientEvent();
1073         event->type             = CE_HUDADD;
1074         event->hudadd.server_id = server_id;
1075         event->hudadd.type      = type;
1076         event->hudadd.pos       = new v2f(pos);
1077         event->hudadd.name      = new std::string(name);
1078         event->hudadd.scale     = new v2f(scale);
1079         event->hudadd.text      = new std::string(text);
1080         event->hudadd.number    = number;
1081         event->hudadd.item      = item;
1082         event->hudadd.dir       = dir;
1083         event->hudadd.align     = new v2f(align);
1084         event->hudadd.offset    = new v2f(offset);
1085         event->hudadd.world_pos = new v3f(world_pos);
1086         event->hudadd.size      = new v2s32(size);
1087         event->hudadd.z_index   = z_index;
1088         event->hudadd.text2     = new std::string(text2);
1089         m_client_event_queue.push(event);
1090 }
1091
1092 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1093 {
1094         u32 server_id;
1095
1096         *pkt >> server_id;
1097
1098         auto i = m_hud_server_to_client.find(server_id);
1099         if (i != m_hud_server_to_client.end()) {
1100                 int client_id = i->second;
1101                 m_hud_server_to_client.erase(i);
1102
1103                 ClientEvent *event = new ClientEvent();
1104                 event->type     = CE_HUDRM;
1105                 event->hudrm.id = client_id;
1106                 m_client_event_queue.push(event);
1107         }
1108 }
1109
1110 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1111 {
1112         std::string sdata;
1113         v2f v2fdata;
1114         v3f v3fdata;
1115         u32 intdata = 0;
1116         v2s32 v2s32data;
1117         u32 server_id;
1118         u8 stat;
1119
1120         *pkt >> server_id >> stat;
1121
1122         if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1123                 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1124                 *pkt >> v2fdata;
1125         else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT || stat == HUD_STAT_TEXT2)
1126                 *pkt >> sdata;
1127         else if (stat == HUD_STAT_WORLD_POS)
1128                 *pkt >> v3fdata;
1129         else if (stat == HUD_STAT_SIZE )
1130                 *pkt >> v2s32data;
1131         else
1132                 *pkt >> intdata;
1133
1134         std::unordered_map<u32, u32>::const_iterator i = m_hud_server_to_client.find(server_id);
1135         if (i != m_hud_server_to_client.end()) {
1136                 ClientEvent *event = new ClientEvent();
1137                 event->type              = CE_HUDCHANGE;
1138                 event->hudchange.id      = i->second;
1139                 event->hudchange.stat    = (HudElementStat)stat;
1140                 event->hudchange.v2fdata = new v2f(v2fdata);
1141                 event->hudchange.v3fdata = new v3f(v3fdata);
1142                 event->hudchange.sdata   = new std::string(sdata);
1143                 event->hudchange.data    = intdata;
1144                 event->hudchange.v2s32data = new v2s32(v2s32data);
1145                 m_client_event_queue.push(event);
1146         }
1147 }
1148
1149 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1150 {
1151         u32 flags, mask;
1152
1153         *pkt >> flags >> mask;
1154
1155         LocalPlayer *player = m_env.getLocalPlayer();
1156         assert(player != NULL);
1157
1158         bool was_minimap_visible = player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE;
1159         bool was_minimap_radar_visible = player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE;
1160
1161         player->hud_flags &= ~mask;
1162         player->hud_flags |= flags;
1163
1164         m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1165         bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1166
1167         // Not so satisying code to keep compatibility with old fixed mode system
1168         // -->
1169
1170         // Hide minimap if it has been disabled by the server
1171         if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible)
1172                 // defers a minimap update, therefore only call it if really
1173                 // needed, by checking that minimap was visible before
1174                 m_minimap->setModeIndex(0);
1175
1176         // If radar has been disabled, try to find a non radar mode or fall back to 0
1177         if (m_minimap && m_minimap_radar_disabled_by_server
1178                         && was_minimap_radar_visible) {
1179                 while (m_minimap->getModeIndex() > 0 &&
1180                                 m_minimap->getModeDef().type == MINIMAP_TYPE_RADAR)
1181                         m_minimap->nextMode();
1182         }
1183         // <--
1184         // End of 'not so satifying code'
1185 }
1186
1187 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1188 {
1189         u16 param; std::string value;
1190
1191         *pkt >> param >> value;
1192
1193         LocalPlayer *player = m_env.getLocalPlayer();
1194         assert(player != NULL);
1195
1196         if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1197                 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1198                 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1199                         player->hud_hotbar_itemcount = hotbar_itemcount;
1200         }
1201         else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1202                 player->hotbar_image = value;
1203         }
1204         else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1205                 player->hotbar_selected_image = value;
1206         }
1207 }
1208
1209 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1210 {
1211         if (m_proto_ver < 39) {
1212                 // Handle Protocol 38 and below servers with old set_sky,
1213                 // ensuring the classic look is kept.
1214                 std::string datastring(pkt->getString(0), pkt->getSize());
1215                 std::istringstream is(datastring, std::ios_base::binary);
1216
1217                 SkyboxParams skybox;
1218                 skybox.bgcolor = video::SColor(readARGB8(is));
1219                 skybox.type = std::string(deSerializeString16(is));
1220                 u16 count = readU16(is);
1221
1222                 for (size_t i = 0; i < count; i++)
1223                         skybox.textures.emplace_back(deSerializeString16(is));
1224
1225                 skybox.clouds = true;
1226                 try {
1227                         skybox.clouds = readU8(is);
1228                 } catch (...) {}
1229
1230                 // Use default skybox settings:
1231                 SkyboxDefaults sky_defaults;
1232                 SunParams sun = sky_defaults.getSunDefaults();
1233                 MoonParams moon = sky_defaults.getMoonDefaults();
1234                 StarParams stars = sky_defaults.getStarDefaults();
1235
1236                 // Fix for "regular" skies, as color isn't kept:
1237                 if (skybox.type == "regular") {
1238                         skybox.sky_color = sky_defaults.getSkyColorDefaults();
1239                         skybox.fog_tint_type = "default";
1240                         skybox.fog_moon_tint = video::SColor(255, 255, 255, 255);
1241                         skybox.fog_sun_tint = video::SColor(255, 255, 255, 255);
1242                 }
1243                 else {
1244                         sun.visible = false;
1245                         sun.sunrise_visible = false;
1246                         moon.visible = false;
1247                         stars.visible = false;
1248                 }
1249
1250                 // Skybox, sun, moon and stars ClientEvents:
1251                 ClientEvent *sky_event = new ClientEvent();
1252                 sky_event->type = CE_SET_SKY;
1253                 sky_event->set_sky = new SkyboxParams(skybox);
1254                 m_client_event_queue.push(sky_event);
1255
1256                 ClientEvent *sun_event = new ClientEvent();
1257                 sun_event->type = CE_SET_SUN;
1258                 sun_event->sun_params = new SunParams(sun);
1259                 m_client_event_queue.push(sun_event);
1260
1261                 ClientEvent *moon_event = new ClientEvent();
1262                 moon_event->type = CE_SET_MOON;
1263                 moon_event->moon_params = new MoonParams(moon);
1264                 m_client_event_queue.push(moon_event);
1265
1266                 ClientEvent *star_event = new ClientEvent();
1267                 star_event->type = CE_SET_STARS;
1268                 star_event->star_params = new StarParams(stars);
1269                 m_client_event_queue.push(star_event);
1270         } else {
1271                 SkyboxParams skybox;
1272                 u16 texture_count;
1273                 std::string texture;
1274
1275                 *pkt >> skybox.bgcolor >> skybox.type >> skybox.clouds >>
1276                         skybox.fog_sun_tint >> skybox.fog_moon_tint >> skybox.fog_tint_type;
1277
1278                 if (skybox.type == "skybox") {
1279                         *pkt >> texture_count;
1280                         for (int i = 0; i < texture_count; i++) {
1281                                 *pkt >> texture;
1282                                 skybox.textures.emplace_back(texture);
1283                         }
1284                 }
1285                 else if (skybox.type == "regular") {
1286                         *pkt >> skybox.sky_color.day_sky >> skybox.sky_color.day_horizon
1287                                 >> skybox.sky_color.dawn_sky >> skybox.sky_color.dawn_horizon
1288                                 >> skybox.sky_color.night_sky >> skybox.sky_color.night_horizon
1289                                 >> skybox.sky_color.indoors;
1290                 }
1291
1292                 ClientEvent *event = new ClientEvent();
1293                 event->type = CE_SET_SKY;
1294                 event->set_sky = new SkyboxParams(skybox);
1295                 m_client_event_queue.push(event);
1296         }
1297 }
1298
1299 void Client::handleCommand_HudSetSun(NetworkPacket *pkt)
1300 {
1301         SunParams sun;
1302
1303         *pkt >> sun.visible >> sun.texture>> sun.tonemap
1304                 >> sun.sunrise >> sun.sunrise_visible >> sun.scale;
1305
1306         ClientEvent *event = new ClientEvent();
1307         event->type        = CE_SET_SUN;
1308         event->sun_params  = new SunParams(sun);
1309         m_client_event_queue.push(event);
1310 }
1311
1312 void Client::handleCommand_HudSetMoon(NetworkPacket *pkt)
1313 {
1314         MoonParams moon;
1315
1316         *pkt >> moon.visible >> moon.texture
1317                 >> moon.tonemap >> moon.scale;
1318
1319         ClientEvent *event = new ClientEvent();
1320         event->type        = CE_SET_MOON;
1321         event->moon_params = new MoonParams(moon);
1322         m_client_event_queue.push(event);
1323 }
1324
1325 void Client::handleCommand_HudSetStars(NetworkPacket *pkt)
1326 {
1327         StarParams stars;
1328
1329         *pkt >> stars.visible >> stars.count
1330                 >> stars.starcolor >> stars.scale;
1331
1332         ClientEvent *event = new ClientEvent();
1333         event->type        = CE_SET_STARS;
1334         event->star_params = new StarParams(stars);
1335
1336         m_client_event_queue.push(event);
1337 }
1338
1339 void Client::handleCommand_CloudParams(NetworkPacket* pkt)
1340 {
1341         f32 density;
1342         video::SColor color_bright;
1343         video::SColor color_ambient;
1344         f32 height;
1345         f32 thickness;
1346         v2f speed;
1347
1348         *pkt >> density >> color_bright >> color_ambient
1349                         >> height >> thickness >> speed;
1350
1351         ClientEvent *event = new ClientEvent();
1352         event->type                       = CE_CLOUD_PARAMS;
1353         event->cloud_params.density       = density;
1354         // use the underlying u32 representation, because we can't
1355         // use struct members with constructors here, and this way
1356         // we avoid using new() and delete() for no good reason
1357         event->cloud_params.color_bright  = color_bright.color;
1358         event->cloud_params.color_ambient = color_ambient.color;
1359         event->cloud_params.height        = height;
1360         event->cloud_params.thickness     = thickness;
1361         // same here: deconstruct to skip constructor
1362         event->cloud_params.speed_x       = speed.X;
1363         event->cloud_params.speed_y       = speed.Y;
1364         m_client_event_queue.push(event);
1365 }
1366
1367 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1368 {
1369         bool do_override;
1370         u16 day_night_ratio_u;
1371
1372         *pkt >> do_override >> day_night_ratio_u;
1373
1374         float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1375
1376         ClientEvent *event = new ClientEvent();
1377         event->type                                 = CE_OVERRIDE_DAY_NIGHT_RATIO;
1378         event->override_day_night_ratio.do_override = do_override;
1379         event->override_day_night_ratio.ratio_f     = day_night_ratio_f;
1380         m_client_event_queue.push(event);
1381 }
1382
1383 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1384 {
1385         LocalPlayer *player = m_env.getLocalPlayer();
1386         assert(player != NULL);
1387
1388         *pkt >> player->local_animations[0];
1389         *pkt >> player->local_animations[1];
1390         *pkt >> player->local_animations[2];
1391         *pkt >> player->local_animations[3];
1392         *pkt >> player->local_animation_speed;
1393 }
1394
1395 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1396 {
1397         LocalPlayer *player = m_env.getLocalPlayer();
1398         assert(player != NULL);
1399
1400         *pkt >> player->eye_offset_first >> player->eye_offset_third;
1401 }
1402
1403 void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt)
1404 {
1405         u8 type;
1406         u16 num_players;
1407         *pkt >> type >> num_players;
1408         PlayerListModifer notice_type = (PlayerListModifer) type;
1409
1410         for (u16 i = 0; i < num_players; i++) {
1411                 std::string name;
1412                 *pkt >> name;
1413                 switch (notice_type) {
1414                 case PLAYER_LIST_INIT:
1415                 case PLAYER_LIST_ADD:
1416                         m_env.addPlayerName(name);
1417                         continue;
1418                 case PLAYER_LIST_REMOVE:
1419                         m_env.removePlayerName(name);
1420                         continue;
1421                 }
1422         }
1423 }
1424
1425 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1426 {
1427         if (m_chosen_auth_mech != AUTH_MECHANISM_SRP &&
1428                         m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
1429                 errorstream << "Client: Received SRP S_B login message,"
1430                         << " but wasn't supposed to (chosen_mech="
1431                         << m_chosen_auth_mech << ")." << std::endl;
1432                 return;
1433         }
1434
1435         char *bytes_M = 0;
1436         size_t len_M = 0;
1437         SRPUser *usr = (SRPUser *) m_auth_data;
1438         std::string s;
1439         std::string B;
1440         *pkt >> s >> B;
1441
1442         infostream << "Client: Received TOCLIENT_SRP_BYTES_S_B." << std::endl;
1443
1444         srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1445                 (const unsigned char *) B.c_str(), B.size(),
1446                 (unsigned char **) &bytes_M, &len_M);
1447
1448         if ( !bytes_M ) {
1449                 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1450                 return;
1451         }
1452
1453         NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1454         resp_pkt << std::string(bytes_M, len_M);
1455         Send(&resp_pkt);
1456 }
1457
1458 void Client::handleCommand_FormspecPrepend(NetworkPacket *pkt)
1459 {
1460         LocalPlayer *player = m_env.getLocalPlayer();
1461         assert(player != NULL);
1462
1463         // Store formspec in LocalPlayer
1464         *pkt >> player->formspec_prepend;
1465 }
1466
1467 void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
1468 {
1469         *pkt >> m_csm_restriction_flags >> m_csm_restriction_noderange;
1470
1471         // Restrictions were received -> load mods if it's enabled
1472         // Note: this should be moved after mods receptions from server instead
1473         loadMods();
1474 }
1475
1476 void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
1477 {
1478         v3f added_vel;
1479
1480         *pkt >> added_vel;
1481
1482         LocalPlayer *player = m_env.getLocalPlayer();
1483         assert(player != NULL);
1484         player->addVelocity(added_vel);
1485 }
1486
1487 void Client::handleCommand_MediaPush(NetworkPacket *pkt)
1488 {
1489         std::string raw_hash, filename, filedata;
1490         bool cached;
1491
1492         *pkt >> raw_hash >> filename >> cached;
1493         filedata = pkt->readLongString();
1494
1495         if (raw_hash.size() != 20 || filedata.empty() || filename.empty() ||
1496                         !string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
1497                 throw PacketError("Illegal filename, data or hash");
1498         }
1499
1500         verbosestream << "Server pushes media file \"" << filename << "\" with "
1501                 << filedata.size() << " bytes of data (cached=" << cached
1502                 << ")" << std::endl;
1503
1504         if (m_media_pushed_files.count(filename) != 0) {
1505                 // Silently ignore for synchronization purposes
1506                 return;
1507         }
1508
1509         // Compute and check checksum of data
1510         std::string computed_hash;
1511         {
1512                 SHA1 ctx;
1513                 ctx.addBytes(filedata.c_str(), filedata.size());
1514                 unsigned char *buf = ctx.getDigest();
1515                 computed_hash.assign((char*) buf, 20);
1516                 free(buf);
1517         }
1518         if (raw_hash != computed_hash) {
1519                 verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
1520                 return;
1521         }
1522
1523         // Actually load media
1524         loadMedia(filedata, filename, true);
1525         m_media_pushed_files.insert(filename);
1526
1527         // Cache file for the next time when this client joins the same server
1528         if (cached)
1529                 clientMediaUpdateCache(raw_hash, filedata);
1530 }
1531
1532 /*
1533  * Mod channels
1534  */
1535
1536 void Client::handleCommand_ModChannelMsg(NetworkPacket *pkt)
1537 {
1538         std::string channel_name, sender, channel_msg;
1539         *pkt >> channel_name >> sender >> channel_msg;
1540
1541         verbosestream << "Mod channel message received from server " << pkt->getPeerId()
1542                 << " on channel " << channel_name << ". sender: `" << sender << "`, message: "
1543                 << channel_msg << std::endl;
1544
1545         if (!m_modchannel_mgr->channelRegistered(channel_name)) {
1546                 verbosestream << "Server sent us messages on unregistered channel "
1547                         << channel_name << ", ignoring." << std::endl;
1548                 return;
1549         }
1550
1551         m_script->on_modchannel_message(channel_name, sender, channel_msg);
1552 }
1553
1554 void Client::handleCommand_ModChannelSignal(NetworkPacket *pkt)
1555 {
1556         u8 signal_tmp;
1557         ModChannelSignal signal;
1558         std::string channel;
1559
1560         *pkt >> signal_tmp >> channel;
1561
1562         signal = (ModChannelSignal)signal_tmp;
1563
1564         bool valid_signal = true;
1565         // @TODO: send Signal to Lua API
1566         switch (signal) {
1567                 case MODCHANNEL_SIGNAL_JOIN_OK:
1568                         m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
1569                         infostream << "Server ack our mod channel join on channel `" << channel
1570                                 << "`, joining." << std::endl;
1571                         break;
1572                 case MODCHANNEL_SIGNAL_JOIN_FAILURE:
1573                         // Unable to join, remove channel
1574                         m_modchannel_mgr->leaveChannel(channel, 0);
1575                         infostream << "Server refused our mod channel join on channel `" << channel
1576                                 << "`" << std::endl;
1577                         break;
1578                 case MODCHANNEL_SIGNAL_LEAVE_OK:
1579 #ifndef NDEBUG
1580                         infostream << "Server ack our mod channel leave on channel " << channel
1581                                 << "`, leaving." << std::endl;
1582 #endif
1583                         break;
1584                 case MODCHANNEL_SIGNAL_LEAVE_FAILURE:
1585                         infostream << "Server refused our mod channel leave on channel `" << channel
1586                                 << "`" << std::endl;
1587                         break;
1588                 case MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED:
1589 #ifndef NDEBUG
1590                         // Generally unused, but ensure we don't do an implementation error
1591                         infostream << "Server tells us we sent a message on channel `" << channel
1592                                 << "` but we are not registered. Message was dropped." << std::endl;
1593 #endif
1594                         break;
1595                 case MODCHANNEL_SIGNAL_SET_STATE: {
1596                         u8 state;
1597                         *pkt >> state;
1598
1599                         if (state == MODCHANNEL_STATE_INIT || state >= MODCHANNEL_STATE_MAX) {
1600                                 infostream << "Received wrong channel state " << state
1601                                                 << ", ignoring." << std::endl;
1602                                 return;
1603                         }
1604
1605                         m_modchannel_mgr->setChannelState(channel, (ModChannelState) state);
1606                         infostream << "Server sets mod channel `" << channel
1607                                         << "` in read-only mode." << std::endl;
1608                         break;
1609                 }
1610                 default:
1611 #ifndef NDEBUG
1612                         warningstream << "Received unhandled mod channel signal ID "
1613                                 << signal << ", ignoring." << std::endl;
1614 #endif
1615                         valid_signal = false;
1616                         break;
1617         }
1618
1619         // If signal is valid, forward it to client side mods
1620         if (valid_signal)
1621                 m_script->on_modchannel_signal(channel, signal);
1622 }
1623
1624 void Client::handleCommand_MinimapModes(NetworkPacket *pkt)
1625 {
1626         u16 count; // modes
1627         u16 mode;  // wanted current mode index after change
1628
1629         *pkt >> count >> mode;
1630
1631         if (m_minimap)
1632                 m_minimap->clearModes();
1633
1634         for (size_t index = 0; index < count; index++) {
1635                 u16 type;
1636                 std::string label;
1637                 u16 size;
1638                 std::string texture;
1639                 u16 scale;
1640
1641                 *pkt >> type >> label >> size >> texture >> scale;
1642
1643                 if (m_minimap)
1644                         m_minimap->addMode(MinimapType(type), size, label, texture, scale);
1645         }
1646
1647         if (m_minimap)
1648                 m_minimap->setModeIndex(mode);
1649 }