3 Copyright (C) 2015 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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.
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.
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.
22 #include "util/base64.h"
23 #include "clientmedia.h"
26 #include "mapsector.h"
29 #include "serialization.h"
32 #include "network/clientopcodes.h"
33 #include "util/serialize.h"
36 void Client::handleCommand_Deprecated(NetworkPacket* pkt)
38 infostream << "Got deprecated command "
39 << toClientCommandTable[pkt->getCommand()].name << " from peer "
40 << pkt->getPeerId() << "!" << std::endl;
43 void Client::handleCommand_Hello(NetworkPacket* pkt)
45 if (pkt->getSize() < 1)
52 std::string username_legacy; // for case insensitivity
53 *pkt >> serialization_ver >> compression_mode >> proto_ver
54 >> auth_mechs >> username_legacy;
56 // Chose an auth method we support
57 AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);
59 infostream << "Client: TOCLIENT_HELLO received with "
60 << "serialization_ver=" << (u32)serialization_ver
61 << ", auth_mechs=" << auth_mechs
62 << ", proto_ver=" << proto_ver
63 << ", compression_mode=" << compression_mode
64 << ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
66 if (!ser_ver_supported(serialization_ver)) {
67 infostream << "Client: TOCLIENT_HELLO: Server sent "
68 << "unsupported ser_fmt_ver"<< std::endl;
72 m_server_ser_ver = serialization_ver;
73 m_proto_ver = proto_ver;
75 //TODO verify that username_legacy matches sent username, only
76 // differs in casing (make both uppercase and compare)
77 // This is only neccessary though when we actually want to add casing support
79 if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
80 // we recieved a TOCLIENT_HELLO while auth was already going on
81 errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
82 << "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
83 if ((m_chosen_auth_mech == AUTH_MECHANISM_SRP)
84 || (m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD)) {
85 srp_user_delete((SRPUser *) m_auth_data);
90 // Authenticate using that method, or abort if there wasn't any method found
91 if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
92 startAuth(chosen_auth_mechanism);
94 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
95 m_access_denied = true;
96 m_access_denied_reason = "Unknown";
102 void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
107 *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
108 >> m_sudo_auth_methods;
110 playerpos -= v3f(0, BS / 2, 0);
112 // Set player position
113 Player *player = m_env.getLocalPlayer();
114 assert(player != NULL);
115 player->setPosition(playerpos);
117 infostream << "Client: received map seed: " << m_map_seed << std::endl;
118 infostream << "Client: received recommended send interval "
119 << m_recommended_send_interval<<std::endl;
122 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
127 void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
131 m_password = m_new_password;
133 verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
135 // send packet to actually set the password
136 startAuth(AUTH_MECHANISM_FIRST_SRP);
139 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
141 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
143 m_chat_queue.push(L"Password change denied. Password NOT changed.");
144 // reset everything and be sad
147 void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
149 if (pkt->getSize() < 1)
153 *pkt >> server_ser_ver;
155 infostream << "Client: TOCLIENT_INIT_LEGACY received with "
156 "server_ser_ver=" << ((int)server_ser_ver & 0xff) << std::endl;
158 if (!ser_ver_supported(server_ser_ver)) {
159 infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent "
160 << "unsupported ser_fmt_ver"<< std::endl;
164 m_server_ser_ver = server_ser_ver;
166 // We can be totally wrong with this guess
167 // but we only need some value < 25.
170 // Get player position
171 v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0);
172 if (pkt->getSize() >= 1 + 6) {
173 *pkt >> playerpos_s16;
175 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0);
178 // Set player position
179 Player *player = m_env.getLocalPlayer();
180 assert(player != NULL);
181 player->setPosition(playerpos_f);
183 if (pkt->getSize() >= 1 + 6 + 8) {
186 infostream << "Client: received map seed: " << m_map_seed << std::endl;
189 if (pkt->getSize() >= 1 + 6 + 8 + 4) {
190 *pkt >> m_recommended_send_interval;
191 infostream << "Client: received recommended send interval "
192 << m_recommended_send_interval<<std::endl;
196 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
202 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
204 // The server didn't like our password. Note, this needs
205 // to be processed even if the serialisation format has
206 // not been agreed yet, the same as TOCLIENT_INIT.
207 m_access_denied = true;
208 m_access_denied_reason = "Unknown";
210 if (pkt->getCommand() == TOCLIENT_ACCESS_DENIED) {
211 if (pkt->getSize() < 1)
214 u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
216 if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN ||
217 denyCode == SERVER_ACCESSDENIED_CRASH) {
218 *pkt >> m_access_denied_reason;
219 if (m_access_denied_reason == "") {
220 m_access_denied_reason = accessDeniedStrings[denyCode];
224 m_access_denied_reconnect = reconnect & 1;
225 } else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
226 *pkt >> m_access_denied_reason;
227 } else if (denyCode < SERVER_ACCESSDENIED_MAX) {
228 m_access_denied_reason = accessDeniedStrings[denyCode];
230 // Allow us to add new error messages to the
231 // protocol without raising the protocol version, if we want to.
232 // Until then (which may be never), this is outside
233 // of the defined protocol.
234 *pkt >> m_access_denied_reason;
235 if (m_access_denied_reason == "") {
236 m_access_denied_reason = "Unknown";
240 // 13/03/15 Legacy code from 0.4.12 and lesser. must stay 1 year
241 // for compat with old clients
243 if (pkt->getSize() >= 2) {
244 std::wstring wide_reason;
246 m_access_denied_reason = wide_to_utf8(wide_reason);
251 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
253 if (pkt->getSize() < 6)
261 void Client::handleCommand_AddNode(NetworkPacket* pkt)
263 if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
270 n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
272 bool remove_metadata = true;
273 u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
274 if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
275 remove_metadata = false;
278 addNode(p, n, remove_metadata);
280 void Client::handleCommand_BlockData(NetworkPacket* pkt)
282 // Ignore too small packet
283 if (pkt->getSize() < 6)
289 std::string datastring(pkt->getString(6), pkt->getSize() - 6);
290 std::istringstream istr(datastring, std::ios_base::binary);
296 sector = m_env.getMap().emergeSector(p2d);
298 assert(sector->getPos() == p2d);
300 block = sector->getBlockNoCreateNoEx(p.Y);
303 Update an existing block
305 block->deSerialize(istr, m_server_ser_ver, false);
306 block->deSerializeNetworkSpecific(istr);
312 block = new MapBlock(&m_env.getMap(), p, this);
313 block->deSerialize(istr, m_server_ser_ver, false);
314 block->deSerializeNetworkSpecific(istr);
315 sector->insertBlock(block);
319 ServerMap::saveBlock(block, m_localdb);
323 Add it to mesh update queue and set it to be acknowledged after update.
325 addUpdateMeshTaskWithEdge(p, true);
328 void Client::handleCommand_Inventory(NetworkPacket* pkt)
330 if (pkt->getSize() < 1)
333 std::string datastring(pkt->getString(0), pkt->getSize());
334 std::istringstream is(datastring, std::ios_base::binary);
336 Player *player = m_env.getLocalPlayer();
337 assert(player != NULL);
339 player->inventory.deSerialize(is);
341 m_inventory_updated = true;
343 delete m_inventory_from_server;
344 m_inventory_from_server = new Inventory(player->inventory);
345 m_inventory_from_server_age = 0.0;
348 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
350 if (pkt->getSize() < 2)
357 time_of_day = time_of_day % 24000;
358 float time_speed = 0;
360 if (pkt->getSize() >= 2 + 4) {
364 // Old message; try to approximate speed of time by ourselves
365 float time_of_day_f = (float)time_of_day / 24000.0;
366 float tod_diff_f = 0;
368 if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
369 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
371 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
373 m_last_time_of_day_f = time_of_day_f;
374 float time_diff = m_time_of_day_update_timer;
375 m_time_of_day_update_timer = 0;
377 if (m_time_of_day_set) {
378 time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff;
379 infostream << "Client: Measured time_of_day speed (old format): "
380 << time_speed << " tod_diff_f=" << tod_diff_f
381 << " time_diff=" << time_diff << std::endl;
385 // Update environment
386 m_env.setTimeOfDay(time_of_day);
387 m_env.setTimeOfDaySpeed(time_speed);
388 m_time_of_day_set = true;
390 u32 dr = m_env.getDayNightRatio();
391 infostream << "Client: time_of_day=" << time_of_day
392 << " time_speed=" << time_speed
393 << " dr=" << dr << std::endl;
396 void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
407 std::wstring message;
408 for (u32 i = 0; i < len; i++) {
410 message += (wchar_t)read_wchar;
413 m_chat_queue.push(message);
416 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
419 u16 count of removed objects
420 for all removed objects {
423 u16 count of added objects
424 for all added objects {
427 u32 initialization data length
428 string initialization data
434 u16 removed_count, added_count, id;
436 // Read removed objects
437 *pkt >> removed_count;
439 for (u16 i = 0; i < removed_count; i++) {
441 m_env.removeActiveObject(id);
444 // Read added objects
447 for (u16 i = 0; i < added_count; i++) {
449 m_env.addActiveObject(id, type, pkt->readLongString());
451 } catch (PacketError &e) {
452 infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
453 << ". The packet is unreliable, ignoring" << std::endl;
457 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
467 std::string datastring(pkt->getString(0), pkt->getSize());
468 std::istringstream is(datastring, std::ios_base::binary);
472 u16 id = readU16(is);
476 std::string message = deSerializeString(is);
478 // Pass on to the environment
479 m_env.processActiveObjectMessage(id, message);
481 } catch (SerializationError &e) {
482 errorstream << "Client::handleCommand_ActiveObjectMessages: "
483 << "caught SerializationError: " << e.what() << std::endl;
487 void Client::handleCommand_Movement(NetworkPacket* pkt)
489 Player *player = m_env.getLocalPlayer();
490 assert(player != NULL);
492 float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
494 *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
495 >> lf >> lfs >> ls >> g;
497 player->movement_acceleration_default = mad * BS;
498 player->movement_acceleration_air = maa * BS;
499 player->movement_acceleration_fast = maf * BS;
500 player->movement_speed_walk = msw * BS;
501 player->movement_speed_crouch = mscr * BS;
502 player->movement_speed_fast = msf * BS;
503 player->movement_speed_climb = mscl * BS;
504 player->movement_speed_jump = msj * BS;
505 player->movement_liquid_fluidity = lf * BS;
506 player->movement_liquid_fluidity_smooth = lfs * BS;
507 player->movement_liquid_sink = ls * BS;
508 player->movement_gravity = g * BS;
511 void Client::handleCommand_HP(NetworkPacket* pkt)
514 Player *player = m_env.getLocalPlayer();
515 assert(player != NULL);
517 u8 oldhp = player->hp;
525 // Add to ClientEvent queue
527 event.type = CE_PLAYER_DAMAGE;
528 event.player_damage.amount = oldhp - hp;
529 m_client_event_queue.push(event);
533 void Client::handleCommand_Breath(NetworkPacket* pkt)
535 Player *player = m_env.getLocalPlayer();
536 assert(player != NULL);
542 player->setBreath(breath);
545 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
547 Player *player = m_env.getLocalPlayer();
548 assert(player != NULL);
553 *pkt >> pos >> pitch >> yaw;
555 player->setPosition(pos);
557 infostream << "Client got TOCLIENT_MOVE_PLAYER"
558 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
559 << " pitch=" << pitch
564 Add to ClientEvent queue.
565 This has to be sent to the main program because otherwise
566 it would just force the pitch and yaw values to whatever
567 the camera points to.
570 event.type = CE_PLAYER_FORCE_MOVE;
571 event.player_force_move.pitch = pitch;
572 event.player_force_move.yaw = yaw;
573 m_client_event_queue.push(event);
575 // Ignore damage for a few seconds, so that the player doesn't
576 // get damage from falling on ground
577 m_ignore_damage_timer = 3.0;
580 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
582 warningstream << "Client: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
585 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
587 bool set_camera_point_target;
588 v3f camera_point_target;
590 *pkt >> set_camera_point_target;
591 *pkt >> camera_point_target;
594 event.type = CE_DEATHSCREEN;
595 event.deathscreen.set_camera_point_target = set_camera_point_target;
596 event.deathscreen.camera_point_target_x = camera_point_target.X;
597 event.deathscreen.camera_point_target_y = camera_point_target.Y;
598 event.deathscreen.camera_point_target_z = camera_point_target.Z;
599 m_client_event_queue.push(event);
602 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
608 infostream << "Client: Received media announcement: packet size: "
609 << pkt->getSize() << std::endl;
611 if (m_media_downloader == NULL ||
612 m_media_downloader->isStarted()) {
613 const char *problem = m_media_downloader ?
614 "we already saw another announcement" :
615 "all media has been received already";
616 errorstream << "Client: Received media announcement but "
618 << " files=" << num_files
619 << " size=" << pkt->getSize() << std::endl;
623 // Mesh update thread must be stopped while
624 // updating content definitions
625 sanity_check(!m_mesh_update_thread.isRunning());
627 for (u16 i = 0; i < num_files; i++) {
628 std::string name, sha1_base64;
630 *pkt >> name >> sha1_base64;
632 std::string sha1_raw = base64_decode(sha1_base64);
633 m_media_downloader->addFile(name, sha1_raw);
636 std::vector<std::string> remote_media;
644 std::string baseurl = trim(sf.next(","));
646 m_media_downloader->addRemoteServer(baseurl);
649 catch(SerializationError& e) {
650 // not supported by server or turned off
653 m_media_downloader->step(this);
656 void Client::handleCommand_Media(NetworkPacket* pkt)
660 u16 total number of file bunches
661 u16 index of this bunch
662 u32 number of files in this bunch
674 *pkt >> num_bunches >> bunch_i >> num_files;
676 infostream << "Client: Received files: bunch " << bunch_i << "/"
677 << num_bunches << " files=" << num_files
678 << " size=" << pkt->getSize() << std::endl;
683 if (m_media_downloader == NULL ||
684 !m_media_downloader->isStarted()) {
685 const char *problem = m_media_downloader ?
686 "media has not been requested" :
687 "all media has been received already";
688 errorstream << "Client: Received media but "
690 << " bunch " << bunch_i << "/" << num_bunches
691 << " files=" << num_files
692 << " size=" << pkt->getSize() << std::endl;
696 // Mesh update thread must be stopped while
697 // updating content definitions
698 sanity_check(!m_mesh_update_thread.isRunning());
700 for (u32 i=0; i < num_files; i++) {
705 std::string data = pkt->readLongString();
707 m_media_downloader->conventionalTransferDone(
712 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
714 warningstream << "Client: Ignoring TOCLIENT_TOOLDEF" << std::endl;
717 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
719 infostream << "Client: Received node definitions: packet size: "
720 << pkt->getSize() << std::endl;
722 // Mesh update thread must be stopped while
723 // updating content definitions
724 sanity_check(!m_mesh_update_thread.isRunning());
726 // Decompress node definitions
727 std::string datastring(pkt->getString(0), pkt->getSize());
728 std::istringstream is(datastring, std::ios_base::binary);
729 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
730 std::ostringstream tmp_os;
731 decompressZlib(tmp_is, tmp_os);
733 // Deserialize node definitions
734 std::istringstream tmp_is2(tmp_os.str());
735 m_nodedef->deSerialize(tmp_is2);
736 m_nodedef_received = true;
739 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
741 warningstream << "Client: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
744 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
746 infostream << "Client: Received item definitions: packet size: "
747 << pkt->getSize() << std::endl;
749 // Mesh update thread must be stopped while
750 // updating content definitions
751 sanity_check(!m_mesh_update_thread.isRunning());
753 // Decompress item definitions
754 std::string datastring(pkt->getString(0), pkt->getSize());
755 std::istringstream is(datastring, std::ios_base::binary);
756 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
757 std::ostringstream tmp_os;
758 decompressZlib(tmp_is, tmp_os);
760 // Deserialize node definitions
761 std::istringstream tmp_is2(tmp_os.str());
762 m_itemdef->deSerialize(tmp_is2);
763 m_itemdef_received = true;
766 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
771 u8 type; // 0=local, 1=positional, 2=object
776 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
782 client_id = m_sound->playSound(name, loop, gain);
784 case 1: // positional
785 client_id = m_sound->playSoundAt(name, loop, gain, pos);
789 ClientActiveObject *cao = m_env.getActiveObject(object_id);
791 pos = cao->getPosition();
792 client_id = m_sound->playSoundAt(name, loop, gain, pos);
793 // TODO: Set up sound to move with object
800 if (client_id != -1) {
801 m_sounds_server_to_client[server_id] = client_id;
802 m_sounds_client_to_server[client_id] = server_id;
804 m_sounds_to_objects[client_id] = object_id;
808 void Client::handleCommand_StopSound(NetworkPacket* pkt)
814 std::map<s32, int>::iterator i =
815 m_sounds_server_to_client.find(server_id);
817 if (i != m_sounds_server_to_client.end()) {
818 int client_id = i->second;
819 m_sound->stopSound(client_id);
823 void Client::handleCommand_Privileges(NetworkPacket* pkt)
825 m_privileges.clear();
826 infostream << "Client: Privileges updated: ";
829 *pkt >> num_privileges;
831 for (u16 i = 0; i < num_privileges; i++) {
836 m_privileges.insert(priv);
837 infostream << priv << " ";
839 infostream << std::endl;
842 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
844 Player *player = m_env.getLocalPlayer();
845 assert(player != NULL);
847 // Store formspec in LocalPlayer
848 player->inventory_formspec = pkt->readLongString();
851 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
853 std::string datastring(pkt->getString(0), pkt->getSize());
854 std::istringstream is(datastring, std::ios_base::binary);
856 std::string name = deSerializeString(is);
858 infostream << "Client: Detached inventory update: \"" << name
859 << "\"" << std::endl;
861 Inventory *inv = NULL;
862 if (m_detached_inventories.count(name) > 0)
863 inv = m_detached_inventories[name];
865 inv = new Inventory(m_itemdef);
866 m_detached_inventories[name] = inv;
868 inv->deSerialize(is);
871 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
873 std::string formspec = pkt->readLongString();
874 std::string formname;
879 event.type = CE_SHOW_FORMSPEC;
880 // pointer is required as event is a struct only!
881 // adding a std:string to a struct isn't possible
882 event.show_formspec.formspec = new std::string(formspec);
883 event.show_formspec.formname = new std::string(formname);
884 m_client_event_queue.push(event);
887 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
889 std::string datastring(pkt->getString(0), pkt->getSize());
890 std::istringstream is(datastring, std::ios_base::binary);
892 v3f pos = readV3F1000(is);
893 v3f vel = readV3F1000(is);
894 v3f acc = readV3F1000(is);
895 float expirationtime = readF1000(is);
896 float size = readF1000(is);
897 bool collisiondetection = readU8(is);
898 std::string texture = deSerializeLongString(is);
899 bool vertical = false;
901 vertical = readU8(is);
905 event.type = CE_SPAWN_PARTICLE;
906 event.spawn_particle.pos = new v3f (pos);
907 event.spawn_particle.vel = new v3f (vel);
908 event.spawn_particle.acc = new v3f (acc);
909 event.spawn_particle.expirationtime = expirationtime;
910 event.spawn_particle.size = size;
911 event.spawn_particle.collisiondetection = collisiondetection;
912 event.spawn_particle.vertical = vertical;
913 event.spawn_particle.texture = new std::string(texture);
915 m_client_event_queue.push(event);
918 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
932 bool collisiondetection;
935 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
936 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
937 >> maxsize >> collisiondetection;
939 std::string texture = pkt->readLongString();
943 bool vertical = false;
949 event.type = CE_ADD_PARTICLESPAWNER;
950 event.add_particlespawner.amount = amount;
951 event.add_particlespawner.spawntime = spawntime;
952 event.add_particlespawner.minpos = new v3f (minpos);
953 event.add_particlespawner.maxpos = new v3f (maxpos);
954 event.add_particlespawner.minvel = new v3f (minvel);
955 event.add_particlespawner.maxvel = new v3f (maxvel);
956 event.add_particlespawner.minacc = new v3f (minacc);
957 event.add_particlespawner.maxacc = new v3f (maxacc);
958 event.add_particlespawner.minexptime = minexptime;
959 event.add_particlespawner.maxexptime = maxexptime;
960 event.add_particlespawner.minsize = minsize;
961 event.add_particlespawner.maxsize = maxsize;
962 event.add_particlespawner.collisiondetection = collisiondetection;
963 event.add_particlespawner.vertical = vertical;
964 event.add_particlespawner.texture = new std::string(texture);
965 event.add_particlespawner.id = id;
967 m_client_event_queue.push(event);
971 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
976 // Modification set 13/03/15, 1 year of compat for protocol v24
977 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
986 event.type = CE_DELETE_PARTICLESPAWNER;
987 event.delete_particlespawner.id =
988 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
990 m_client_event_queue.push(event);
993 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
995 std::string datastring(pkt->getString(0), pkt->getSize());
996 std::istringstream is(datastring, std::ios_base::binary);
1012 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
1013 >> dir >> align >> offset;
1017 catch(SerializationError &e) {};
1021 } catch(SerializationError &e) {};
1024 event.type = CE_HUDADD;
1025 event.hudadd.id = id;
1026 event.hudadd.type = type;
1027 event.hudadd.pos = new v2f(pos);
1028 event.hudadd.name = new std::string(name);
1029 event.hudadd.scale = new v2f(scale);
1030 event.hudadd.text = new std::string(text);
1031 event.hudadd.number = number;
1032 event.hudadd.item = item;
1033 event.hudadd.dir = dir;
1034 event.hudadd.align = new v2f(align);
1035 event.hudadd.offset = new v2f(offset);
1036 event.hudadd.world_pos = new v3f(world_pos);
1037 event.hudadd.size = new v2s32(size);
1038 m_client_event_queue.push(event);
1041 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1048 event.type = CE_HUDRM;
1049 event.hudrm.id = id;
1050 m_client_event_queue.push(event);
1053 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1065 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1066 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1068 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1070 else if (stat == HUD_STAT_WORLD_POS)
1072 else if (stat == HUD_STAT_SIZE )
1078 event.type = CE_HUDCHANGE;
1079 event.hudchange.id = id;
1080 event.hudchange.stat = (HudElementStat)stat;
1081 event.hudchange.v2fdata = new v2f(v2fdata);
1082 event.hudchange.v3fdata = new v3f(v3fdata);
1083 event.hudchange.sdata = new std::string(sdata);
1084 event.hudchange.data = intdata;
1085 event.hudchange.v2s32data = new v2s32(v2s32data);
1086 m_client_event_queue.push(event);
1089 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1093 *pkt >> flags >> mask;
1095 Player *player = m_env.getLocalPlayer();
1096 assert(player != NULL);
1098 bool was_minimap_visible = player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE;
1100 player->hud_flags &= ~mask;
1101 player->hud_flags |= flags;
1103 m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1105 // Hide minimap if it has been disabled by the server
1106 if (m_minimap_disabled_by_server && was_minimap_visible) {
1107 // defers a minimap update, therefore only call it if really
1108 // needed, by checking that minimap was visible before
1109 m_mapper->setMinimapMode(MINIMAP_MODE_OFF);
1113 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1115 u16 param; std::string value;
1117 *pkt >> param >> value;
1119 Player *player = m_env.getLocalPlayer();
1120 assert(player != NULL);
1122 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1123 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1124 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1125 player->hud_hotbar_itemcount = hotbar_itemcount;
1127 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1128 ((LocalPlayer *) player)->hotbar_image = value;
1130 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1131 ((LocalPlayer *) player)->hotbar_selected_image = value;
1135 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1137 std::string datastring(pkt->getString(0), pkt->getSize());
1138 std::istringstream is(datastring, std::ios_base::binary);
1140 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1141 std::string *type = new std::string(deSerializeString(is));
1142 u16 count = readU16(is);
1143 std::vector<std::string> *params = new std::vector<std::string>;
1145 for (size_t i = 0; i < count; i++)
1146 params->push_back(deSerializeString(is));
1149 event.type = CE_SET_SKY;
1150 event.set_sky.bgcolor = bgcolor;
1151 event.set_sky.type = type;
1152 event.set_sky.params = params;
1153 m_client_event_queue.push(event);
1156 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1159 u16 day_night_ratio_u;
1161 *pkt >> do_override >> day_night_ratio_u;
1163 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1166 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1167 event.override_day_night_ratio.do_override = do_override;
1168 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1169 m_client_event_queue.push(event);
1172 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1174 LocalPlayer *player = m_env.getLocalPlayer();
1175 assert(player != NULL);
1177 *pkt >> player->local_animations[0];
1178 *pkt >> player->local_animations[1];
1179 *pkt >> player->local_animations[2];
1180 *pkt >> player->local_animations[3];
1181 *pkt >> player->local_animation_speed;
1184 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1186 LocalPlayer *player = m_env.getLocalPlayer();
1187 assert(player != NULL);
1189 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1192 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1194 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1195 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1196 errorstream << "Client: Recieved SRP S_B login message,"
1197 << " but wasn't supposed to (chosen_mech="
1198 << m_chosen_auth_mech << ")." << std::endl;
1204 SRPUser *usr = (SRPUser *) m_auth_data;
1209 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1211 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1212 (const unsigned char *) B.c_str(), B.size(),
1213 (unsigned char **) &bytes_M, &len_M);
1216 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1220 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1221 resp_pkt << std::string(bytes_M, len_M);