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