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"
31 #include "util/strfnd.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 LocalPlayer *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 LocalPlayer *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 LocalPlayer *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 LocalPlayer *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 LocalPlayer *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 LocalPlayer *player = m_env.getLocalPlayer();
536 assert(player != NULL);
542 player->setBreath(breath);
545 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
547 LocalPlayer *player = m_env.getLocalPlayer();
548 assert(player != NULL);
553 *pkt >> pos >> pitch >> yaw;
555 player->got_teleported = true;
556 player->setPosition(pos);
558 infostream << "Client got TOCLIENT_MOVE_PLAYER"
559 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
560 << " pitch=" << pitch
565 Add to ClientEvent queue.
566 This has to be sent to the main program because otherwise
567 it would just force the pitch and yaw values to whatever
568 the camera points to.
571 event.type = CE_PLAYER_FORCE_MOVE;
572 event.player_force_move.pitch = pitch;
573 event.player_force_move.yaw = yaw;
574 m_client_event_queue.push(event);
576 // Ignore damage for a few seconds, so that the player doesn't
577 // get damage from falling on ground
578 m_ignore_damage_timer = 3.0;
581 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
583 warningstream << "Client: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
586 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
588 bool set_camera_point_target;
589 v3f camera_point_target;
591 *pkt >> set_camera_point_target;
592 *pkt >> camera_point_target;
595 event.type = CE_DEATHSCREEN;
596 event.deathscreen.set_camera_point_target = set_camera_point_target;
597 event.deathscreen.camera_point_target_x = camera_point_target.X;
598 event.deathscreen.camera_point_target_y = camera_point_target.Y;
599 event.deathscreen.camera_point_target_z = camera_point_target.Z;
600 m_client_event_queue.push(event);
603 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
609 infostream << "Client: Received media announcement: packet size: "
610 << pkt->getSize() << std::endl;
612 if (m_media_downloader == NULL ||
613 m_media_downloader->isStarted()) {
614 const char *problem = m_media_downloader ?
615 "we already saw another announcement" :
616 "all media has been received already";
617 errorstream << "Client: Received media announcement but "
619 << " files=" << num_files
620 << " size=" << pkt->getSize() << std::endl;
624 // Mesh update thread must be stopped while
625 // updating content definitions
626 sanity_check(!m_mesh_update_thread.isRunning());
628 for (u16 i = 0; i < num_files; i++) {
629 std::string name, sha1_base64;
631 *pkt >> name >> sha1_base64;
633 std::string sha1_raw = base64_decode(sha1_base64);
634 m_media_downloader->addFile(name, sha1_raw);
637 std::vector<std::string> remote_media;
644 while(!sf.at_end()) {
645 std::string baseurl = trim(sf.next(","));
647 m_media_downloader->addRemoteServer(baseurl);
650 catch(SerializationError& e) {
651 // not supported by server or turned off
654 m_media_downloader->step(this);
657 void Client::handleCommand_Media(NetworkPacket* pkt)
661 u16 total number of file bunches
662 u16 index of this bunch
663 u32 number of files in this bunch
675 *pkt >> num_bunches >> bunch_i >> num_files;
677 infostream << "Client: Received files: bunch " << bunch_i << "/"
678 << num_bunches << " files=" << num_files
679 << " size=" << pkt->getSize() << std::endl;
684 if (m_media_downloader == NULL ||
685 !m_media_downloader->isStarted()) {
686 const char *problem = m_media_downloader ?
687 "media has not been requested" :
688 "all media has been received already";
689 errorstream << "Client: Received media but "
691 << " bunch " << bunch_i << "/" << num_bunches
692 << " files=" << num_files
693 << " size=" << pkt->getSize() << std::endl;
697 // Mesh update thread must be stopped while
698 // updating content definitions
699 sanity_check(!m_mesh_update_thread.isRunning());
701 for (u32 i=0; i < num_files; i++) {
706 std::string data = pkt->readLongString();
708 m_media_downloader->conventionalTransferDone(
713 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
715 warningstream << "Client: Ignoring TOCLIENT_TOOLDEF" << std::endl;
718 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
720 infostream << "Client: Received node definitions: packet size: "
721 << pkt->getSize() << std::endl;
723 // Mesh update thread must be stopped while
724 // updating content definitions
725 sanity_check(!m_mesh_update_thread.isRunning());
727 // Decompress node definitions
728 std::string datastring(pkt->getString(0), pkt->getSize());
729 std::istringstream is(datastring, std::ios_base::binary);
730 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
731 std::ostringstream tmp_os;
732 decompressZlib(tmp_is, tmp_os);
734 // Deserialize node definitions
735 std::istringstream tmp_is2(tmp_os.str());
736 m_nodedef->deSerialize(tmp_is2);
737 m_nodedef_received = true;
740 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
742 warningstream << "Client: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
745 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
747 infostream << "Client: Received item definitions: packet size: "
748 << pkt->getSize() << std::endl;
750 // Mesh update thread must be stopped while
751 // updating content definitions
752 sanity_check(!m_mesh_update_thread.isRunning());
754 // Decompress item definitions
755 std::string datastring(pkt->getString(0), pkt->getSize());
756 std::istringstream is(datastring, std::ios_base::binary);
757 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
758 std::ostringstream tmp_os;
759 decompressZlib(tmp_is, tmp_os);
761 // Deserialize node definitions
762 std::istringstream tmp_is2(tmp_os.str());
763 m_itemdef->deSerialize(tmp_is2);
764 m_itemdef_received = true;
767 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
772 u8 type; // 0=local, 1=positional, 2=object
777 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
783 client_id = m_sound->playSound(name, loop, gain);
785 case 1: // positional
786 client_id = m_sound->playSoundAt(name, loop, gain, pos);
790 ClientActiveObject *cao = m_env.getActiveObject(object_id);
792 pos = cao->getPosition();
793 client_id = m_sound->playSoundAt(name, loop, gain, pos);
794 // TODO: Set up sound to move with object
801 if (client_id != -1) {
802 m_sounds_server_to_client[server_id] = client_id;
803 m_sounds_client_to_server[client_id] = server_id;
805 m_sounds_to_objects[client_id] = object_id;
809 void Client::handleCommand_StopSound(NetworkPacket* pkt)
815 UNORDERED_MAP<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
816 if (i != m_sounds_server_to_client.end()) {
817 int client_id = i->second;
818 m_sound->stopSound(client_id);
822 void Client::handleCommand_Privileges(NetworkPacket* pkt)
824 m_privileges.clear();
825 infostream << "Client: Privileges updated: ";
828 *pkt >> num_privileges;
830 for (u16 i = 0; i < num_privileges; i++) {
835 m_privileges.insert(priv);
836 infostream << priv << " ";
838 infostream << std::endl;
841 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
843 LocalPlayer *player = m_env.getLocalPlayer();
844 assert(player != NULL);
846 // Store formspec in LocalPlayer
847 player->inventory_formspec = pkt->readLongString();
850 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
852 std::string datastring(pkt->getString(0), pkt->getSize());
853 std::istringstream is(datastring, std::ios_base::binary);
855 std::string name = deSerializeString(is);
857 infostream << "Client: Detached inventory update: \"" << name
858 << "\"" << std::endl;
860 Inventory *inv = NULL;
861 if (m_detached_inventories.count(name) > 0)
862 inv = m_detached_inventories[name];
864 inv = new Inventory(m_itemdef);
865 m_detached_inventories[name] = inv;
867 inv->deSerialize(is);
870 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
872 std::string formspec = pkt->readLongString();
873 std::string formname;
878 event.type = CE_SHOW_FORMSPEC;
879 // pointer is required as event is a struct only!
880 // adding a std:string to a struct isn't possible
881 event.show_formspec.formspec = new std::string(formspec);
882 event.show_formspec.formname = new std::string(formname);
883 m_client_event_queue.push(event);
886 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
888 std::string datastring(pkt->getString(0), pkt->getSize());
889 std::istringstream is(datastring, std::ios_base::binary);
891 v3f pos = readV3F1000(is);
892 v3f vel = readV3F1000(is);
893 v3f acc = readV3F1000(is);
894 float expirationtime = readF1000(is);
895 float size = readF1000(is);
896 bool collisiondetection = readU8(is);
897 std::string texture = deSerializeLongString(is);
898 bool vertical = false;
899 bool collision_removal = false;
901 vertical = readU8(is);
902 collision_removal = readU8(is);
906 event.type = CE_SPAWN_PARTICLE;
907 event.spawn_particle.pos = new v3f (pos);
908 event.spawn_particle.vel = new v3f (vel);
909 event.spawn_particle.acc = new v3f (acc);
910 event.spawn_particle.expirationtime = expirationtime;
911 event.spawn_particle.size = size;
912 event.spawn_particle.collisiondetection = collisiondetection;
913 event.spawn_particle.collision_removal = collision_removal;
914 event.spawn_particle.vertical = vertical;
915 event.spawn_particle.texture = new std::string(texture);
917 m_client_event_queue.push(event);
920 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
934 bool collisiondetection;
937 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
938 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
939 >> maxsize >> collisiondetection;
941 std::string texture = pkt->readLongString();
945 bool vertical = false;
946 bool collision_removal = false;
950 *pkt >> collision_removal;
956 event.type = CE_ADD_PARTICLESPAWNER;
957 event.add_particlespawner.amount = amount;
958 event.add_particlespawner.spawntime = spawntime;
959 event.add_particlespawner.minpos = new v3f (minpos);
960 event.add_particlespawner.maxpos = new v3f (maxpos);
961 event.add_particlespawner.minvel = new v3f (minvel);
962 event.add_particlespawner.maxvel = new v3f (maxvel);
963 event.add_particlespawner.minacc = new v3f (minacc);
964 event.add_particlespawner.maxacc = new v3f (maxacc);
965 event.add_particlespawner.minexptime = minexptime;
966 event.add_particlespawner.maxexptime = maxexptime;
967 event.add_particlespawner.minsize = minsize;
968 event.add_particlespawner.maxsize = maxsize;
969 event.add_particlespawner.collisiondetection = collisiondetection;
970 event.add_particlespawner.collision_removal = collision_removal;
971 event.add_particlespawner.attached_id = attached_id;
972 event.add_particlespawner.vertical = vertical;
973 event.add_particlespawner.texture = new std::string(texture);
974 event.add_particlespawner.id = id;
976 m_client_event_queue.push(event);
980 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
985 // Modification set 13/03/15, 1 year of compat for protocol v24
986 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
995 event.type = CE_DELETE_PARTICLESPAWNER;
996 event.delete_particlespawner.id =
997 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
999 m_client_event_queue.push(event);
1002 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
1004 std::string datastring(pkt->getString(0), pkt->getSize());
1005 std::istringstream is(datastring, std::ios_base::binary);
1021 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
1022 >> dir >> align >> offset;
1026 catch(SerializationError &e) {};
1030 } catch(SerializationError &e) {};
1033 event.type = CE_HUDADD;
1034 event.hudadd.id = id;
1035 event.hudadd.type = type;
1036 event.hudadd.pos = new v2f(pos);
1037 event.hudadd.name = new std::string(name);
1038 event.hudadd.scale = new v2f(scale);
1039 event.hudadd.text = new std::string(text);
1040 event.hudadd.number = number;
1041 event.hudadd.item = item;
1042 event.hudadd.dir = dir;
1043 event.hudadd.align = new v2f(align);
1044 event.hudadd.offset = new v2f(offset);
1045 event.hudadd.world_pos = new v3f(world_pos);
1046 event.hudadd.size = new v2s32(size);
1047 m_client_event_queue.push(event);
1050 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1057 event.type = CE_HUDRM;
1058 event.hudrm.id = id;
1059 m_client_event_queue.push(event);
1062 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1074 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1075 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1077 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1079 else if (stat == HUD_STAT_WORLD_POS)
1081 else if (stat == HUD_STAT_SIZE )
1087 event.type = CE_HUDCHANGE;
1088 event.hudchange.id = id;
1089 event.hudchange.stat = (HudElementStat)stat;
1090 event.hudchange.v2fdata = new v2f(v2fdata);
1091 event.hudchange.v3fdata = new v3f(v3fdata);
1092 event.hudchange.sdata = new std::string(sdata);
1093 event.hudchange.data = intdata;
1094 event.hudchange.v2s32data = new v2s32(v2s32data);
1095 m_client_event_queue.push(event);
1098 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1102 *pkt >> flags >> mask;
1104 LocalPlayer *player = m_env.getLocalPlayer();
1105 assert(player != NULL);
1107 bool was_minimap_visible = player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE;
1109 player->hud_flags &= ~mask;
1110 player->hud_flags |= flags;
1112 m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1114 // Hide minimap if it has been disabled by the server
1115 if (m_minimap_disabled_by_server && was_minimap_visible) {
1116 // defers a minimap update, therefore only call it if really
1117 // needed, by checking that minimap was visible before
1118 m_mapper->setMinimapMode(MINIMAP_MODE_OFF);
1122 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1124 u16 param; std::string value;
1126 *pkt >> param >> value;
1128 LocalPlayer *player = m_env.getLocalPlayer();
1129 assert(player != NULL);
1131 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1132 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1133 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1134 player->hud_hotbar_itemcount = hotbar_itemcount;
1136 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1137 player->hotbar_image = value;
1139 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1140 player->hotbar_selected_image = value;
1144 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1146 std::string datastring(pkt->getString(0), pkt->getSize());
1147 std::istringstream is(datastring, std::ios_base::binary);
1149 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1150 std::string *type = new std::string(deSerializeString(is));
1151 u16 count = readU16(is);
1152 std::vector<std::string> *params = new std::vector<std::string>;
1154 for (size_t i = 0; i < count; i++)
1155 params->push_back(deSerializeString(is));
1158 event.type = CE_SET_SKY;
1159 event.set_sky.bgcolor = bgcolor;
1160 event.set_sky.type = type;
1161 event.set_sky.params = params;
1162 m_client_event_queue.push(event);
1165 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1168 u16 day_night_ratio_u;
1170 *pkt >> do_override >> day_night_ratio_u;
1172 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1175 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1176 event.override_day_night_ratio.do_override = do_override;
1177 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1178 m_client_event_queue.push(event);
1181 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1183 LocalPlayer *player = m_env.getLocalPlayer();
1184 assert(player != NULL);
1186 *pkt >> player->local_animations[0];
1187 *pkt >> player->local_animations[1];
1188 *pkt >> player->local_animations[2];
1189 *pkt >> player->local_animations[3];
1190 *pkt >> player->local_animation_speed;
1193 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1195 LocalPlayer *player = m_env.getLocalPlayer();
1196 assert(player != NULL);
1198 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1201 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1203 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1204 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1205 errorstream << "Client: Recieved SRP S_B login message,"
1206 << " but wasn't supposed to (chosen_mech="
1207 << m_chosen_auth_mech << ")." << std::endl;
1213 SRPUser *usr = (SRPUser *) m_auth_data;
1218 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1220 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1221 (const unsigned char *) B.c_str(), B.size(),
1222 (unsigned char **) &bytes_M, &len_M);
1225 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1229 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1230 resp_pkt << std::string(bytes_M, len_M);