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"
28 #include "serialization.h"
31 #include "network/clientopcodes.h"
32 #include "util/serialize.h"
35 void Client::handleCommand_Deprecated(NetworkPacket* pkt)
37 infostream << "Got deprecated command "
38 << toClientCommandTable[pkt->getCommand()].name << " from peer "
39 << pkt->getPeerId() << "!" << std::endl;
42 void Client::handleCommand_Hello(NetworkPacket* pkt)
44 if (pkt->getSize() < 1)
49 std::string username_legacy; // for case insensitivity
50 *pkt >> deployed >> auth_mechs >> username_legacy;
52 // Chose an auth method we support
53 AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);
55 infostream << "Client: TOCLIENT_HELLO received with "
56 "deployed=" << ((int)deployed & 0xff) << ", auth_mechs="
57 << auth_mechs << ", chosen=" << chosen_auth_mechanism << std::endl;
59 if (!ser_ver_supported(deployed)) {
60 infostream << "Client: TOCLIENT_HELLO: Server sent "
61 << "unsupported ser_fmt_ver"<< std::endl;
65 m_server_ser_ver = deployed;
66 m_proto_ver = deployed;
68 //TODO verify that username_legacy matches sent username, only
69 // differs in casing (make both uppercase and compare)
70 // This is only neccessary though when we actually want to add casing support
72 if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
73 // we recieved a TOCLIENT_HELLO while auth was already going on
74 errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
75 << "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
76 if ((m_chosen_auth_mech == AUTH_MECHANISM_SRP)
77 || (m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD)) {
78 srp_user_delete((SRPUser *) m_auth_data);
83 // Authenticate using that method, or abort if there wasn't any method found
84 if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
85 startAuth(chosen_auth_mechanism);
87 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
88 m_access_denied = true;
89 m_access_denied_reason = "Unknown";
95 void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
97 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
101 *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
102 >> m_sudo_auth_methods;
104 playerpos -= v3f(0, BS / 2, 0);
106 // Set player position
107 Player *player = m_env.getLocalPlayer();
108 assert(player != NULL);
109 player->setPosition(playerpos);
111 infostream << "Client: received map seed: " << m_map_seed << std::endl;
112 infostream << "Client: received recommended send interval "
113 << m_recommended_send_interval<<std::endl;
116 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
121 void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
123 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
126 m_password = m_new_password;
128 verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
130 // send packet to actually set the password
131 startAuth(AUTH_MECHANISM_FIRST_SRP);
134 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
136 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
138 m_chat_queue.push(L"Password change denied. Password NOT changed.");
139 // reset everything and be sad
141 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
143 void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
145 if (pkt->getSize() < 1)
151 infostream << "Client: TOCLIENT_INIT_LEGACY received with "
152 "deployed=" << ((int)deployed & 0xff) << std::endl;
154 if (!ser_ver_supported(deployed)) {
155 infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent "
156 << "unsupported ser_fmt_ver"<< std::endl;
160 m_server_ser_ver = deployed;
161 m_proto_ver = deployed;
163 // Get player position
164 v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0);
165 if (pkt->getSize() >= 1 + 6) {
166 *pkt >> playerpos_s16;
168 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0);
171 // Set player position
172 Player *player = m_env.getLocalPlayer();
173 assert(player != NULL);
174 player->setPosition(playerpos_f);
176 if (pkt->getSize() >= 1 + 6 + 8) {
179 infostream << "Client: received map seed: " << m_map_seed << std::endl;
182 if (pkt->getSize() >= 1 + 6 + 8 + 4) {
183 *pkt >> m_recommended_send_interval;
184 infostream << "Client: received recommended send interval "
185 << m_recommended_send_interval<<std::endl;
189 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
195 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
197 // The server didn't like our password. Note, this needs
198 // to be processed even if the serialisation format has
199 // not been agreed yet, the same as TOCLIENT_INIT.
200 m_access_denied = true;
201 m_access_denied_reason = "Unknown";
203 if (pkt->getCommand() == TOCLIENT_ACCESS_DENIED) {
204 if (pkt->getSize() < 1)
207 u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
209 if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
210 *pkt >> m_access_denied_reason;
212 else if (denyCode < SERVER_ACCESSDENIED_MAX) {
213 m_access_denied_reason = accessDeniedStrings[denyCode];
216 // 13/03/15 Legacy code from 0.4.12 and lesser. must stay 1 year
217 // for compat with old clients
219 if (pkt->getSize() >= 2) {
220 std::wstring wide_reason;
222 m_access_denied_reason = wide_to_narrow(wide_reason);
227 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
229 if (pkt->getSize() < 6)
237 void Client::handleCommand_AddNode(NetworkPacket* pkt)
239 if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
246 n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
248 bool remove_metadata = true;
249 u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
250 if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
251 remove_metadata = false;
254 addNode(p, n, remove_metadata);
256 void Client::handleCommand_BlockData(NetworkPacket* pkt)
258 // Ignore too small packet
259 if (pkt->getSize() < 6)
265 std::string datastring(pkt->getString(6), pkt->getSize() - 6);
266 std::istringstream istr(datastring, std::ios_base::binary);
272 sector = m_env.getMap().emergeSector(p2d);
274 assert(sector->getPos() == p2d);
276 block = sector->getBlockNoCreateNoEx(p.Y);
279 Update an existing block
281 block->deSerialize(istr, m_server_ser_ver, false);
282 block->deSerializeNetworkSpecific(istr);
288 block = new MapBlock(&m_env.getMap(), p, this);
289 block->deSerialize(istr, m_server_ser_ver, false);
290 block->deSerializeNetworkSpecific(istr);
291 sector->insertBlock(block);
295 ServerMap::saveBlock(block, m_localdb);
299 Add it to mesh update queue and set it to be acknowledged after update.
301 addUpdateMeshTaskWithEdge(p, true);
304 void Client::handleCommand_Inventory(NetworkPacket* pkt)
306 if (pkt->getSize() < 1)
309 std::string datastring(pkt->getString(0), pkt->getSize());
310 std::istringstream is(datastring, std::ios_base::binary);
312 Player *player = m_env.getLocalPlayer();
313 assert(player != NULL);
315 player->inventory.deSerialize(is);
317 m_inventory_updated = true;
319 delete m_inventory_from_server;
320 m_inventory_from_server = new Inventory(player->inventory);
321 m_inventory_from_server_age = 0.0;
324 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
326 if (pkt->getSize() < 2)
333 time_of_day = time_of_day % 24000;
334 float time_speed = 0;
336 if (pkt->getSize() >= 2 + 4) {
340 // Old message; try to approximate speed of time by ourselves
341 float time_of_day_f = (float)time_of_day / 24000.0;
342 float tod_diff_f = 0;
344 if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
345 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
347 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
349 m_last_time_of_day_f = time_of_day_f;
350 float time_diff = m_time_of_day_update_timer;
351 m_time_of_day_update_timer = 0;
353 if (m_time_of_day_set) {
354 time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff;
355 infostream << "Client: Measured time_of_day speed (old format): "
356 << time_speed << " tod_diff_f=" << tod_diff_f
357 << " time_diff=" << time_diff << std::endl;
361 // Update environment
362 m_env.setTimeOfDay(time_of_day);
363 m_env.setTimeOfDaySpeed(time_speed);
364 m_time_of_day_set = true;
366 u32 dr = m_env.getDayNightRatio();
367 infostream << "Client: time_of_day=" << time_of_day
368 << " time_speed=" << time_speed
369 << " dr=" << dr << std::endl;
372 void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
383 std::wstring message;
384 for (u32 i = 0; i < len; i++) {
386 message += (wchar_t)read_wchar;
389 m_chat_queue.push(message);
392 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
395 u16 count of removed objects
396 for all removed objects {
399 u16 count of added objects
400 for all added objects {
403 u32 initialization data length
404 string initialization data
410 u16 removed_count, added_count, id;
412 // Read removed objects
413 *pkt >> removed_count;
415 for (u16 i = 0; i < removed_count; i++) {
417 m_env.removeActiveObject(id);
420 // Read added objects
423 for (u16 i = 0; i < added_count; i++) {
425 m_env.addActiveObject(id, type, pkt->readLongString());
427 } catch (PacketError &e) {
428 infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
429 << ". The packet is unreliable, ignoring" << std::endl;
433 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
444 // Get all data except the command number
445 std::string datastring(pkt->getString(0), pkt->getSize());
446 // Throw them in an istringstream
447 std::istringstream is(datastring, std::ios_base::binary);
450 while(is.eof() == false) {
452 u16 id = readU16((u8*)buf);
456 size_t message_size = readU16((u8*)buf);
458 message.reserve(message_size);
459 for (u32 i = 0; i < message_size; i++) {
461 message.append(buf, 1);
463 // Pass on to the environment
464 m_env.processActiveObjectMessage(id, message);
466 // Packet could be unreliable then ignore it
467 } catch (PacketError &e) {
468 infostream << "handleCommand_ActiveObjectMessages: " << e.what()
469 << ". The packet is unreliable, ignoring" << std::endl;
473 void Client::handleCommand_Movement(NetworkPacket* pkt)
475 Player *player = m_env.getLocalPlayer();
476 assert(player != NULL);
478 float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
480 *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
481 >> lf >> lfs >> ls >> g;
483 player->movement_acceleration_default = mad * BS;
484 player->movement_acceleration_air = maa * BS;
485 player->movement_acceleration_fast = maf * BS;
486 player->movement_speed_walk = msw * BS;
487 player->movement_speed_crouch = mscr * BS;
488 player->movement_speed_fast = msf * BS;
489 player->movement_speed_climb = mscl * BS;
490 player->movement_speed_jump = msj * BS;
491 player->movement_liquid_fluidity = lf * BS;
492 player->movement_liquid_fluidity_smooth = lfs * BS;
493 player->movement_liquid_sink = ls * BS;
494 player->movement_gravity = g * BS;
497 void Client::handleCommand_HP(NetworkPacket* pkt)
500 Player *player = m_env.getLocalPlayer();
501 assert(player != NULL);
503 u8 oldhp = player->hp;
511 // Add to ClientEvent queue
513 event.type = CE_PLAYER_DAMAGE;
514 event.player_damage.amount = oldhp - hp;
515 m_client_event_queue.push(event);
519 void Client::handleCommand_Breath(NetworkPacket* pkt)
521 Player *player = m_env.getLocalPlayer();
522 assert(player != NULL);
528 player->setBreath(breath);
531 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
533 Player *player = m_env.getLocalPlayer();
534 assert(player != NULL);
539 *pkt >> pos >> pitch >> yaw;
541 player->setPosition(pos);
543 infostream << "Client got TOCLIENT_MOVE_PLAYER"
544 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
545 << " pitch=" << pitch
550 Add to ClientEvent queue.
551 This has to be sent to the main program because otherwise
552 it would just force the pitch and yaw values to whatever
553 the camera points to.
556 event.type = CE_PLAYER_FORCE_MOVE;
557 event.player_force_move.pitch = pitch;
558 event.player_force_move.yaw = yaw;
559 m_client_event_queue.push(event);
561 // Ignore damage for a few seconds, so that the player doesn't
562 // get damage from falling on ground
563 m_ignore_damage_timer = 3.0;
566 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
568 infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
571 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
573 bool set_camera_point_target;
574 v3f camera_point_target;
576 *pkt >> set_camera_point_target;
577 *pkt >> camera_point_target;
580 event.type = CE_DEATHSCREEN;
581 event.deathscreen.set_camera_point_target = set_camera_point_target;
582 event.deathscreen.camera_point_target_x = camera_point_target.X;
583 event.deathscreen.camera_point_target_y = camera_point_target.Y;
584 event.deathscreen.camera_point_target_z = camera_point_target.Z;
585 m_client_event_queue.push(event);
588 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
594 infostream << "Client: Received media announcement: packet size: "
595 << pkt->getSize() << std::endl;
597 if (m_media_downloader == NULL ||
598 m_media_downloader->isStarted()) {
599 const char *problem = m_media_downloader ?
600 "we already saw another announcement" :
601 "all media has been received already";
602 errorstream << "Client: Received media announcement but "
604 << " files=" << num_files
605 << " size=" << pkt->getSize() << std::endl;
609 // Mesh update thread must be stopped while
610 // updating content definitions
611 sanity_check(!m_mesh_update_thread.IsRunning());
613 for (u16 i = 0; i < num_files; i++) {
614 std::string name, sha1_base64;
616 *pkt >> name >> sha1_base64;
618 std::string sha1_raw = base64_decode(sha1_base64);
619 m_media_downloader->addFile(name, sha1_raw);
622 std::vector<std::string> remote_media;
630 std::string baseurl = trim(sf.next(","));
632 m_media_downloader->addRemoteServer(baseurl);
635 catch(SerializationError& e) {
636 // not supported by server or turned off
639 m_media_downloader->step(this);
642 void Client::handleCommand_Media(NetworkPacket* pkt)
646 u16 total number of file bunches
647 u16 index of this bunch
648 u32 number of files in this bunch
660 *pkt >> num_bunches >> bunch_i >> num_files;
662 infostream << "Client: Received files: bunch " << bunch_i << "/"
663 << num_bunches << " files=" << num_files
664 << " size=" << pkt->getSize() << std::endl;
669 if (m_media_downloader == NULL ||
670 !m_media_downloader->isStarted()) {
671 const char *problem = m_media_downloader ?
672 "media has not been requested" :
673 "all media has been received already";
674 errorstream << "Client: Received media but "
676 << " bunch " << bunch_i << "/" << num_bunches
677 << " files=" << num_files
678 << " size=" << pkt->getSize() << std::endl;
682 // Mesh update thread must be stopped while
683 // updating content definitions
684 sanity_check(!m_mesh_update_thread.IsRunning());
686 for (u32 i=0; i < num_files; i++) {
691 std::string data = pkt->readLongString();
693 m_media_downloader->conventionalTransferDone(
698 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
700 infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl;
703 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
705 infostream << "Client: Received node definitions: packet size: "
706 << pkt->getSize() << std::endl;
708 // Mesh update thread must be stopped while
709 // updating content definitions
710 sanity_check(!m_mesh_update_thread.IsRunning());
712 // Decompress node definitions
713 std::string datastring(pkt->getString(0), pkt->getSize());
714 std::istringstream is(datastring, std::ios_base::binary);
715 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
716 std::ostringstream tmp_os;
717 decompressZlib(tmp_is, tmp_os);
719 // Deserialize node definitions
720 std::istringstream tmp_is2(tmp_os.str());
721 m_nodedef->deSerialize(tmp_is2);
722 m_nodedef_received = true;
725 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
727 infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
730 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
732 infostream << "Client: Received item definitions: packet size: "
733 << pkt->getSize() << std::endl;
735 // Mesh update thread must be stopped while
736 // updating content definitions
737 sanity_check(!m_mesh_update_thread.IsRunning());
739 // Decompress item definitions
740 std::string datastring(pkt->getString(0), pkt->getSize());
741 std::istringstream is(datastring, std::ios_base::binary);
742 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
743 std::ostringstream tmp_os;
744 decompressZlib(tmp_is, tmp_os);
746 // Deserialize node definitions
747 std::istringstream tmp_is2(tmp_os.str());
748 m_itemdef->deSerialize(tmp_is2);
749 m_itemdef_received = true;
752 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
757 u8 type; // 0=local, 1=positional, 2=object
762 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
768 client_id = m_sound->playSound(name, loop, gain);
770 case 1: // positional
771 client_id = m_sound->playSoundAt(name, loop, gain, pos);
775 ClientActiveObject *cao = m_env.getActiveObject(object_id);
777 pos = cao->getPosition();
778 client_id = m_sound->playSoundAt(name, loop, gain, pos);
779 // TODO: Set up sound to move with object
786 if (client_id != -1) {
787 m_sounds_server_to_client[server_id] = client_id;
788 m_sounds_client_to_server[client_id] = server_id;
790 m_sounds_to_objects[client_id] = object_id;
794 void Client::handleCommand_StopSound(NetworkPacket* pkt)
800 std::map<s32, int>::iterator i =
801 m_sounds_server_to_client.find(server_id);
803 if (i != m_sounds_server_to_client.end()) {
804 int client_id = i->second;
805 m_sound->stopSound(client_id);
809 void Client::handleCommand_Privileges(NetworkPacket* pkt)
811 m_privileges.clear();
812 infostream << "Client: Privileges updated: ";
815 *pkt >> num_privileges;
817 for (u16 i = 0; i < num_privileges; i++) {
822 m_privileges.insert(priv);
823 infostream << priv << " ";
825 infostream << std::endl;
828 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
830 Player *player = m_env.getLocalPlayer();
831 assert(player != NULL);
833 // Store formspec in LocalPlayer
834 player->inventory_formspec = pkt->readLongString();
837 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
839 std::string datastring(pkt->getString(0), pkt->getSize());
840 std::istringstream is(datastring, std::ios_base::binary);
842 std::string name = deSerializeString(is);
844 infostream << "Client: Detached inventory update: \"" << name
845 << "\"" << std::endl;
847 Inventory *inv = NULL;
848 if (m_detached_inventories.count(name) > 0)
849 inv = m_detached_inventories[name];
851 inv = new Inventory(m_itemdef);
852 m_detached_inventories[name] = inv;
854 inv->deSerialize(is);
857 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
859 std::string formspec = pkt->readLongString();
860 std::string formname;
865 event.type = CE_SHOW_FORMSPEC;
866 // pointer is required as event is a struct only!
867 // adding a std:string to a struct isn't possible
868 event.show_formspec.formspec = new std::string(formspec);
869 event.show_formspec.formname = new std::string(formname);
870 m_client_event_queue.push(event);
873 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
875 std::string datastring(pkt->getString(0), pkt->getSize());
876 std::istringstream is(datastring, std::ios_base::binary);
878 v3f pos = readV3F1000(is);
879 v3f vel = readV3F1000(is);
880 v3f acc = readV3F1000(is);
881 float expirationtime = readF1000(is);
882 float size = readF1000(is);
883 bool collisiondetection = readU8(is);
884 std::string texture = deSerializeLongString(is);
885 bool vertical = false;
887 vertical = readU8(is);
891 event.type = CE_SPAWN_PARTICLE;
892 event.spawn_particle.pos = new v3f (pos);
893 event.spawn_particle.vel = new v3f (vel);
894 event.spawn_particle.acc = new v3f (acc);
895 event.spawn_particle.expirationtime = expirationtime;
896 event.spawn_particle.size = size;
897 event.spawn_particle.collisiondetection = collisiondetection;
898 event.spawn_particle.vertical = vertical;
899 event.spawn_particle.texture = new std::string(texture);
901 m_client_event_queue.push(event);
904 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
918 bool collisiondetection;
921 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
922 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
923 >> maxsize >> collisiondetection;
925 std::string texture = pkt->readLongString();
929 bool vertical = false;
935 event.type = CE_ADD_PARTICLESPAWNER;
936 event.add_particlespawner.amount = amount;
937 event.add_particlespawner.spawntime = spawntime;
938 event.add_particlespawner.minpos = new v3f (minpos);
939 event.add_particlespawner.maxpos = new v3f (maxpos);
940 event.add_particlespawner.minvel = new v3f (minvel);
941 event.add_particlespawner.maxvel = new v3f (maxvel);
942 event.add_particlespawner.minacc = new v3f (minacc);
943 event.add_particlespawner.maxacc = new v3f (maxacc);
944 event.add_particlespawner.minexptime = minexptime;
945 event.add_particlespawner.maxexptime = maxexptime;
946 event.add_particlespawner.minsize = minsize;
947 event.add_particlespawner.maxsize = maxsize;
948 event.add_particlespawner.collisiondetection = collisiondetection;
949 event.add_particlespawner.vertical = vertical;
950 event.add_particlespawner.texture = new std::string(texture);
951 event.add_particlespawner.id = id;
953 m_client_event_queue.push(event);
957 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
962 // Modification set 13/03/15, 1 year of compat for protocol v24
963 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
972 event.type = CE_DELETE_PARTICLESPAWNER;
973 event.delete_particlespawner.id =
974 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
976 m_client_event_queue.push(event);
979 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
981 std::string datastring(pkt->getString(0), pkt->getSize());
982 std::istringstream is(datastring, std::ios_base::binary);
998 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
999 >> dir >> align >> offset;
1003 catch(SerializationError &e) {};
1007 } catch(SerializationError &e) {};
1010 event.type = CE_HUDADD;
1011 event.hudadd.id = id;
1012 event.hudadd.type = type;
1013 event.hudadd.pos = new v2f(pos);
1014 event.hudadd.name = new std::string(name);
1015 event.hudadd.scale = new v2f(scale);
1016 event.hudadd.text = new std::string(text);
1017 event.hudadd.number = number;
1018 event.hudadd.item = item;
1019 event.hudadd.dir = dir;
1020 event.hudadd.align = new v2f(align);
1021 event.hudadd.offset = new v2f(offset);
1022 event.hudadd.world_pos = new v3f(world_pos);
1023 event.hudadd.size = new v2s32(size);
1024 m_client_event_queue.push(event);
1027 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1034 event.type = CE_HUDRM;
1035 event.hudrm.id = id;
1036 m_client_event_queue.push(event);
1039 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1051 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1052 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1054 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1056 else if (stat == HUD_STAT_WORLD_POS)
1058 else if (stat == HUD_STAT_SIZE )
1064 event.type = CE_HUDCHANGE;
1065 event.hudchange.id = id;
1066 event.hudchange.stat = (HudElementStat)stat;
1067 event.hudchange.v2fdata = new v2f(v2fdata);
1068 event.hudchange.v3fdata = new v3f(v3fdata);
1069 event.hudchange.sdata = new std::string(sdata);
1070 event.hudchange.data = intdata;
1071 event.hudchange.v2s32data = new v2s32(v2s32data);
1072 m_client_event_queue.push(event);
1075 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1079 *pkt >> flags >> mask;
1081 Player *player = m_env.getLocalPlayer();
1082 assert(player != NULL);
1084 player->hud_flags &= ~mask;
1085 player->hud_flags |= flags;
1088 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1090 u16 param; std::string value;
1092 *pkt >> param >> value;
1094 Player *player = m_env.getLocalPlayer();
1095 assert(player != NULL);
1097 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1098 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1099 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1100 player->hud_hotbar_itemcount = hotbar_itemcount;
1102 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1103 ((LocalPlayer *) player)->hotbar_image = value;
1105 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1106 ((LocalPlayer *) player)->hotbar_selected_image = value;
1110 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1112 std::string datastring(pkt->getString(0), pkt->getSize());
1113 std::istringstream is(datastring, std::ios_base::binary);
1115 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1116 std::string *type = new std::string(deSerializeString(is));
1117 u16 count = readU16(is);
1118 std::vector<std::string> *params = new std::vector<std::string>;
1120 for (size_t i = 0; i < count; i++)
1121 params->push_back(deSerializeString(is));
1124 event.type = CE_SET_SKY;
1125 event.set_sky.bgcolor = bgcolor;
1126 event.set_sky.type = type;
1127 event.set_sky.params = params;
1128 m_client_event_queue.push(event);
1131 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1134 u16 day_night_ratio_u;
1136 *pkt >> do_override >> day_night_ratio_u;
1138 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1141 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1142 event.override_day_night_ratio.do_override = do_override;
1143 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1144 m_client_event_queue.push(event);
1147 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1149 LocalPlayer *player = m_env.getLocalPlayer();
1150 assert(player != NULL);
1152 *pkt >> player->local_animations[0];
1153 *pkt >> player->local_animations[1];
1154 *pkt >> player->local_animations[2];
1155 *pkt >> player->local_animations[3];
1156 *pkt >> player->local_animation_speed;
1159 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1161 LocalPlayer *player = m_env.getLocalPlayer();
1162 assert(player != NULL);
1164 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1167 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1169 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1170 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1171 errorstream << "Client: Recieved SRP S_B login message,"
1172 << " but wasn't supposed to (chosen_mech="
1173 << m_chosen_auth_mech << ")." << std::endl;
1179 SRPUser *usr = (SRPUser *) m_auth_data;
1184 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1186 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1187 (const unsigned char *) B.c_str(), B.size(),
1188 (unsigned char **) &bytes_M, &len_M);
1191 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1195 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1196 resp_pkt << std::string(bytes_M, len_M);