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);
643 while(!sf.at_end()) {
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 UNORDERED_MAP<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
815 if (i != m_sounds_server_to_client.end()) {
816 int client_id = i->second;
817 m_sound->stopSound(client_id);
821 void Client::handleCommand_Privileges(NetworkPacket* pkt)
823 m_privileges.clear();
824 infostream << "Client: Privileges updated: ";
827 *pkt >> num_privileges;
829 for (u16 i = 0; i < num_privileges; i++) {
834 m_privileges.insert(priv);
835 infostream << priv << " ";
837 infostream << std::endl;
840 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
842 LocalPlayer *player = m_env.getLocalPlayer();
843 assert(player != NULL);
845 // Store formspec in LocalPlayer
846 player->inventory_formspec = pkt->readLongString();
849 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
851 std::string datastring(pkt->getString(0), pkt->getSize());
852 std::istringstream is(datastring, std::ios_base::binary);
854 std::string name = deSerializeString(is);
856 infostream << "Client: Detached inventory update: \"" << name
857 << "\"" << std::endl;
859 Inventory *inv = NULL;
860 if (m_detached_inventories.count(name) > 0)
861 inv = m_detached_inventories[name];
863 inv = new Inventory(m_itemdef);
864 m_detached_inventories[name] = inv;
866 inv->deSerialize(is);
869 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
871 std::string formspec = pkt->readLongString();
872 std::string formname;
877 event.type = CE_SHOW_FORMSPEC;
878 // pointer is required as event is a struct only!
879 // adding a std:string to a struct isn't possible
880 event.show_formspec.formspec = new std::string(formspec);
881 event.show_formspec.formname = new std::string(formname);
882 m_client_event_queue.push(event);
885 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
887 std::string datastring(pkt->getString(0), pkt->getSize());
888 std::istringstream is(datastring, std::ios_base::binary);
890 v3f pos = readV3F1000(is);
891 v3f vel = readV3F1000(is);
892 v3f acc = readV3F1000(is);
893 float expirationtime = readF1000(is);
894 float size = readF1000(is);
895 bool collisiondetection = readU8(is);
896 std::string texture = deSerializeLongString(is);
897 bool vertical = false;
898 bool collision_removal = false;
900 vertical = readU8(is);
901 collision_removal = 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.collision_removal = collision_removal;
913 event.spawn_particle.vertical = vertical;
914 event.spawn_particle.texture = new std::string(texture);
916 m_client_event_queue.push(event);
919 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
933 bool collisiondetection;
936 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
937 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
938 >> maxsize >> collisiondetection;
940 std::string texture = pkt->readLongString();
944 bool vertical = false;
945 bool collision_removal = false;
949 *pkt >> collision_removal;
955 event.type = CE_ADD_PARTICLESPAWNER;
956 event.add_particlespawner.amount = amount;
957 event.add_particlespawner.spawntime = spawntime;
958 event.add_particlespawner.minpos = new v3f (minpos);
959 event.add_particlespawner.maxpos = new v3f (maxpos);
960 event.add_particlespawner.minvel = new v3f (minvel);
961 event.add_particlespawner.maxvel = new v3f (maxvel);
962 event.add_particlespawner.minacc = new v3f (minacc);
963 event.add_particlespawner.maxacc = new v3f (maxacc);
964 event.add_particlespawner.minexptime = minexptime;
965 event.add_particlespawner.maxexptime = maxexptime;
966 event.add_particlespawner.minsize = minsize;
967 event.add_particlespawner.maxsize = maxsize;
968 event.add_particlespawner.collisiondetection = collisiondetection;
969 event.add_particlespawner.collision_removal = collision_removal;
970 event.add_particlespawner.attached_id = attached_id;
971 event.add_particlespawner.vertical = vertical;
972 event.add_particlespawner.texture = new std::string(texture);
973 event.add_particlespawner.id = id;
975 m_client_event_queue.push(event);
979 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
984 // Modification set 13/03/15, 1 year of compat for protocol v24
985 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
994 event.type = CE_DELETE_PARTICLESPAWNER;
995 event.delete_particlespawner.id =
996 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
998 m_client_event_queue.push(event);
1001 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
1003 std::string datastring(pkt->getString(0), pkt->getSize());
1004 std::istringstream is(datastring, std::ios_base::binary);
1020 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
1021 >> dir >> align >> offset;
1025 catch(SerializationError &e) {};
1029 } catch(SerializationError &e) {};
1032 event.type = CE_HUDADD;
1033 event.hudadd.id = id;
1034 event.hudadd.type = type;
1035 event.hudadd.pos = new v2f(pos);
1036 event.hudadd.name = new std::string(name);
1037 event.hudadd.scale = new v2f(scale);
1038 event.hudadd.text = new std::string(text);
1039 event.hudadd.number = number;
1040 event.hudadd.item = item;
1041 event.hudadd.dir = dir;
1042 event.hudadd.align = new v2f(align);
1043 event.hudadd.offset = new v2f(offset);
1044 event.hudadd.world_pos = new v3f(world_pos);
1045 event.hudadd.size = new v2s32(size);
1046 m_client_event_queue.push(event);
1049 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1056 event.type = CE_HUDRM;
1057 event.hudrm.id = id;
1058 m_client_event_queue.push(event);
1061 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1073 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1074 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1076 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1078 else if (stat == HUD_STAT_WORLD_POS)
1080 else if (stat == HUD_STAT_SIZE )
1086 event.type = CE_HUDCHANGE;
1087 event.hudchange.id = id;
1088 event.hudchange.stat = (HudElementStat)stat;
1089 event.hudchange.v2fdata = new v2f(v2fdata);
1090 event.hudchange.v3fdata = new v3f(v3fdata);
1091 event.hudchange.sdata = new std::string(sdata);
1092 event.hudchange.data = intdata;
1093 event.hudchange.v2s32data = new v2s32(v2s32data);
1094 m_client_event_queue.push(event);
1097 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1101 *pkt >> flags >> mask;
1103 LocalPlayer *player = m_env.getLocalPlayer();
1104 assert(player != NULL);
1106 bool was_minimap_visible = player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE;
1108 player->hud_flags &= ~mask;
1109 player->hud_flags |= flags;
1111 m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1113 // Hide minimap if it has been disabled by the server
1114 if (m_minimap_disabled_by_server && was_minimap_visible) {
1115 // defers a minimap update, therefore only call it if really
1116 // needed, by checking that minimap was visible before
1117 m_mapper->setMinimapMode(MINIMAP_MODE_OFF);
1121 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1123 u16 param; std::string value;
1125 *pkt >> param >> value;
1127 LocalPlayer *player = m_env.getLocalPlayer();
1128 assert(player != NULL);
1130 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1131 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1132 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1133 player->hud_hotbar_itemcount = hotbar_itemcount;
1135 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1136 player->hotbar_image = value;
1138 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1139 player->hotbar_selected_image = value;
1143 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1145 std::string datastring(pkt->getString(0), pkt->getSize());
1146 std::istringstream is(datastring, std::ios_base::binary);
1148 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1149 std::string *type = new std::string(deSerializeString(is));
1150 u16 count = readU16(is);
1151 std::vector<std::string> *params = new std::vector<std::string>;
1153 for (size_t i = 0; i < count; i++)
1154 params->push_back(deSerializeString(is));
1157 event.type = CE_SET_SKY;
1158 event.set_sky.bgcolor = bgcolor;
1159 event.set_sky.type = type;
1160 event.set_sky.params = params;
1161 m_client_event_queue.push(event);
1164 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1167 u16 day_night_ratio_u;
1169 *pkt >> do_override >> day_night_ratio_u;
1171 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1174 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1175 event.override_day_night_ratio.do_override = do_override;
1176 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1177 m_client_event_queue.push(event);
1180 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1182 LocalPlayer *player = m_env.getLocalPlayer();
1183 assert(player != NULL);
1185 *pkt >> player->local_animations[0];
1186 *pkt >> player->local_animations[1];
1187 *pkt >> player->local_animations[2];
1188 *pkt >> player->local_animations[3];
1189 *pkt >> player->local_animation_speed;
1192 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1194 LocalPlayer *player = m_env.getLocalPlayer();
1195 assert(player != NULL);
1197 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1200 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1202 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1203 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1204 errorstream << "Client: Recieved SRP S_B login message,"
1205 << " but wasn't supposed to (chosen_mech="
1206 << m_chosen_auth_mech << ")." << std::endl;
1212 SRPUser *usr = (SRPUser *) m_auth_data;
1217 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1219 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1220 (const unsigned char *) B.c_str(), B.size(),
1221 (unsigned char **) &bytes_M, &len_M);
1224 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1228 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1229 resp_pkt << std::string(bytes_M, len_M);