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