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