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)
51 std::string username_legacy; // for case insensitivity
52 *pkt >> serialization_ver >> compression_mode >> proto_ver
53 >> auth_mechs >> username_legacy;
55 // Chose an auth method we support
56 AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);
58 infostream << "Client: TOCLIENT_HELLO recieved with "
59 << "serialization_ver=" << (u32)serialization_ver
60 << ", auth_mechs=" << auth_mechs
61 << ", proto_ver=" << proto_ver
62 << ", compression_mode=" << compression_mode
63 << ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
65 if (!ser_ver_supported(serialization_ver)) {
66 infostream << "Client: TOCLIENT_HELLO: Server sent "
67 << "unsupported ser_fmt_ver"<< std::endl;
71 m_server_ser_ver = serialization_ver;
72 m_proto_ver = proto_ver;
74 //TODO verify that username_legacy matches sent username, only
75 // differs in casing (make both uppercase and compare)
76 // This is only neccessary though when we actually want to add casing support
78 if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
79 // we recieved a TOCLIENT_HELLO while auth was already going on
80 errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
81 << "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
82 if ((m_chosen_auth_mech == AUTH_MECHANISM_SRP)
83 || (m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD)) {
84 srp_user_delete((SRPUser *) m_auth_data);
89 // Authenticate using that method, or abort if there wasn't any method found
90 if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
91 startAuth(chosen_auth_mechanism);
93 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
94 m_access_denied = true;
95 m_access_denied_reason = "Unknown";
101 void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
103 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
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)
129 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
132 m_password = m_new_password;
134 verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
136 // send packet to actually set the password
137 startAuth(AUTH_MECHANISM_FIRST_SRP);
140 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
142 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
144 m_chat_queue.push(L"Password change denied. Password NOT changed.");
145 // reset everything and be sad
147 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
149 void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
151 if (pkt->getSize() < 1)
157 infostream << "Client: TOCLIENT_INIT_LEGACY received with "
158 "deployed=" << ((int)deployed & 0xff) << std::endl;
160 if (!ser_ver_supported(deployed)) {
161 infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent "
162 << "unsupported ser_fmt_ver"<< std::endl;
166 m_server_ser_ver = deployed;
167 m_proto_ver = deployed;
169 // Get player position
170 v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0);
171 if (pkt->getSize() >= 1 + 6) {
172 *pkt >> playerpos_s16;
174 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0);
177 // Set player position
178 Player *player = m_env.getLocalPlayer();
179 assert(player != NULL);
180 player->setPosition(playerpos_f);
182 if (pkt->getSize() >= 1 + 6 + 8) {
185 infostream << "Client: received map seed: " << m_map_seed << std::endl;
188 if (pkt->getSize() >= 1 + 6 + 8 + 4) {
189 *pkt >> m_recommended_send_interval;
190 infostream << "Client: received recommended send interval "
191 << m_recommended_send_interval<<std::endl;
195 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
201 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
203 // The server didn't like our password. Note, this needs
204 // to be processed even if the serialisation format has
205 // not been agreed yet, the same as TOCLIENT_INIT.
206 m_access_denied = true;
207 m_access_denied_reason = "Unknown";
209 if (pkt->getCommand() == TOCLIENT_ACCESS_DENIED) {
210 if (pkt->getSize() < 1)
213 u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
215 if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
216 *pkt >> m_access_denied_reason;
218 else if (denyCode < SERVER_ACCESSDENIED_MAX) {
219 m_access_denied_reason = accessDeniedStrings[denyCode];
222 // 13/03/15 Legacy code from 0.4.12 and lesser. must stay 1 year
223 // for compat with old clients
225 if (pkt->getSize() >= 2) {
226 std::wstring wide_reason;
228 m_access_denied_reason = wide_to_narrow(wide_reason);
233 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
235 if (pkt->getSize() < 6)
243 void Client::handleCommand_AddNode(NetworkPacket* pkt)
245 if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
252 n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
254 bool remove_metadata = true;
255 u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
256 if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
257 remove_metadata = false;
260 addNode(p, n, remove_metadata);
262 void Client::handleCommand_BlockData(NetworkPacket* pkt)
264 // Ignore too small packet
265 if (pkt->getSize() < 6)
271 std::string datastring(pkt->getString(6), pkt->getSize() - 6);
272 std::istringstream istr(datastring, std::ios_base::binary);
278 sector = m_env.getMap().emergeSector(p2d);
280 assert(sector->getPos() == p2d);
282 block = sector->getBlockNoCreateNoEx(p.Y);
285 Update an existing block
287 block->deSerialize(istr, m_server_ser_ver, false);
288 block->deSerializeNetworkSpecific(istr);
294 block = new MapBlock(&m_env.getMap(), p, this);
295 block->deSerialize(istr, m_server_ser_ver, false);
296 block->deSerializeNetworkSpecific(istr);
297 sector->insertBlock(block);
301 ServerMap::saveBlock(block, m_localdb);
305 Add it to mesh update queue and set it to be acknowledged after update.
307 addUpdateMeshTaskWithEdge(p, true);
310 void Client::handleCommand_Inventory(NetworkPacket* pkt)
312 if (pkt->getSize() < 1)
315 std::string datastring(pkt->getString(0), pkt->getSize());
316 std::istringstream is(datastring, std::ios_base::binary);
318 Player *player = m_env.getLocalPlayer();
319 assert(player != NULL);
321 player->inventory.deSerialize(is);
323 m_inventory_updated = true;
325 delete m_inventory_from_server;
326 m_inventory_from_server = new Inventory(player->inventory);
327 m_inventory_from_server_age = 0.0;
330 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
332 if (pkt->getSize() < 2)
339 time_of_day = time_of_day % 24000;
340 float time_speed = 0;
342 if (pkt->getSize() >= 2 + 4) {
346 // Old message; try to approximate speed of time by ourselves
347 float time_of_day_f = (float)time_of_day / 24000.0;
348 float tod_diff_f = 0;
350 if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
351 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
353 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
355 m_last_time_of_day_f = time_of_day_f;
356 float time_diff = m_time_of_day_update_timer;
357 m_time_of_day_update_timer = 0;
359 if (m_time_of_day_set) {
360 time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff;
361 infostream << "Client: Measured time_of_day speed (old format): "
362 << time_speed << " tod_diff_f=" << tod_diff_f
363 << " time_diff=" << time_diff << std::endl;
367 // Update environment
368 m_env.setTimeOfDay(time_of_day);
369 m_env.setTimeOfDaySpeed(time_speed);
370 m_time_of_day_set = true;
372 u32 dr = m_env.getDayNightRatio();
373 infostream << "Client: time_of_day=" << time_of_day
374 << " time_speed=" << time_speed
375 << " dr=" << dr << std::endl;
378 void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
389 std::wstring message;
390 for (u32 i = 0; i < len; i++) {
392 message += (wchar_t)read_wchar;
395 m_chat_queue.push(message);
398 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
401 u16 count of removed objects
402 for all removed objects {
405 u16 count of added objects
406 for all added objects {
409 u32 initialization data length
410 string initialization data
416 u16 removed_count, added_count, id;
418 // Read removed objects
419 *pkt >> removed_count;
421 for (u16 i = 0; i < removed_count; i++) {
423 m_env.removeActiveObject(id);
426 // Read added objects
429 for (u16 i = 0; i < added_count; i++) {
431 m_env.addActiveObject(id, type, pkt->readLongString());
433 } catch (PacketError &e) {
434 infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
435 << ". The packet is unreliable, ignoring" << std::endl;
439 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
450 // Get all data except the command number
451 std::string datastring(pkt->getString(0), pkt->getSize());
452 // Throw them in an istringstream
453 std::istringstream is(datastring, std::ios_base::binary);
456 while(is.eof() == false) {
458 u16 id = readU16((u8*)buf);
462 size_t message_size = readU16((u8*)buf);
464 message.reserve(message_size);
465 for (u32 i = 0; i < message_size; i++) {
467 message.append(buf, 1);
469 // Pass on to the environment
470 m_env.processActiveObjectMessage(id, message);
472 // Packet could be unreliable then ignore it
473 } catch (PacketError &e) {
474 infostream << "handleCommand_ActiveObjectMessages: " << e.what()
475 << ". The packet is unreliable, ignoring" << std::endl;
479 void Client::handleCommand_Movement(NetworkPacket* pkt)
481 Player *player = m_env.getLocalPlayer();
482 assert(player != NULL);
484 float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
486 *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
487 >> lf >> lfs >> ls >> g;
489 player->movement_acceleration_default = mad * BS;
490 player->movement_acceleration_air = maa * BS;
491 player->movement_acceleration_fast = maf * BS;
492 player->movement_speed_walk = msw * BS;
493 player->movement_speed_crouch = mscr * BS;
494 player->movement_speed_fast = msf * BS;
495 player->movement_speed_climb = mscl * BS;
496 player->movement_speed_jump = msj * BS;
497 player->movement_liquid_fluidity = lf * BS;
498 player->movement_liquid_fluidity_smooth = lfs * BS;
499 player->movement_liquid_sink = ls * BS;
500 player->movement_gravity = g * BS;
503 void Client::handleCommand_HP(NetworkPacket* pkt)
506 Player *player = m_env.getLocalPlayer();
507 assert(player != NULL);
509 u8 oldhp = player->hp;
517 // Add to ClientEvent queue
519 event.type = CE_PLAYER_DAMAGE;
520 event.player_damage.amount = oldhp - hp;
521 m_client_event_queue.push(event);
525 void Client::handleCommand_Breath(NetworkPacket* pkt)
527 Player *player = m_env.getLocalPlayer();
528 assert(player != NULL);
534 player->setBreath(breath);
537 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
539 Player *player = m_env.getLocalPlayer();
540 assert(player != NULL);
545 *pkt >> pos >> pitch >> yaw;
547 player->setPosition(pos);
549 infostream << "Client got TOCLIENT_MOVE_PLAYER"
550 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
551 << " pitch=" << pitch
556 Add to ClientEvent queue.
557 This has to be sent to the main program because otherwise
558 it would just force the pitch and yaw values to whatever
559 the camera points to.
562 event.type = CE_PLAYER_FORCE_MOVE;
563 event.player_force_move.pitch = pitch;
564 event.player_force_move.yaw = yaw;
565 m_client_event_queue.push(event);
567 // Ignore damage for a few seconds, so that the player doesn't
568 // get damage from falling on ground
569 m_ignore_damage_timer = 3.0;
572 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
574 infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
577 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
579 bool set_camera_point_target;
580 v3f camera_point_target;
582 *pkt >> set_camera_point_target;
583 *pkt >> camera_point_target;
586 event.type = CE_DEATHSCREEN;
587 event.deathscreen.set_camera_point_target = set_camera_point_target;
588 event.deathscreen.camera_point_target_x = camera_point_target.X;
589 event.deathscreen.camera_point_target_y = camera_point_target.Y;
590 event.deathscreen.camera_point_target_z = camera_point_target.Z;
591 m_client_event_queue.push(event);
594 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
600 infostream << "Client: Received media announcement: packet size: "
601 << pkt->getSize() << std::endl;
603 if (m_media_downloader == NULL ||
604 m_media_downloader->isStarted()) {
605 const char *problem = m_media_downloader ?
606 "we already saw another announcement" :
607 "all media has been received already";
608 errorstream << "Client: Received media announcement but "
610 << " files=" << num_files
611 << " size=" << pkt->getSize() << std::endl;
615 // Mesh update thread must be stopped while
616 // updating content definitions
617 sanity_check(!m_mesh_update_thread.IsRunning());
619 for (u16 i = 0; i < num_files; i++) {
620 std::string name, sha1_base64;
622 *pkt >> name >> sha1_base64;
624 std::string sha1_raw = base64_decode(sha1_base64);
625 m_media_downloader->addFile(name, sha1_raw);
628 std::vector<std::string> remote_media;
636 std::string baseurl = trim(sf.next(","));
638 m_media_downloader->addRemoteServer(baseurl);
641 catch(SerializationError& e) {
642 // not supported by server or turned off
645 m_media_downloader->step(this);
648 void Client::handleCommand_Media(NetworkPacket* pkt)
652 u16 total number of file bunches
653 u16 index of this bunch
654 u32 number of files in this bunch
666 *pkt >> num_bunches >> bunch_i >> num_files;
668 infostream << "Client: Received files: bunch " << bunch_i << "/"
669 << num_bunches << " files=" << num_files
670 << " size=" << pkt->getSize() << std::endl;
675 if (m_media_downloader == NULL ||
676 !m_media_downloader->isStarted()) {
677 const char *problem = m_media_downloader ?
678 "media has not been requested" :
679 "all media has been received already";
680 errorstream << "Client: Received media but "
682 << " bunch " << bunch_i << "/" << num_bunches
683 << " files=" << num_files
684 << " size=" << pkt->getSize() << std::endl;
688 // Mesh update thread must be stopped while
689 // updating content definitions
690 sanity_check(!m_mesh_update_thread.IsRunning());
692 for (u32 i=0; i < num_files; i++) {
697 std::string data = pkt->readLongString();
699 m_media_downloader->conventionalTransferDone(
704 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
706 infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl;
709 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
711 infostream << "Client: Received node definitions: packet size: "
712 << pkt->getSize() << std::endl;
714 // Mesh update thread must be stopped while
715 // updating content definitions
716 sanity_check(!m_mesh_update_thread.IsRunning());
718 // Decompress node definitions
719 std::string datastring(pkt->getString(0), pkt->getSize());
720 std::istringstream is(datastring, std::ios_base::binary);
721 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
722 std::ostringstream tmp_os;
723 decompressZlib(tmp_is, tmp_os);
725 // Deserialize node definitions
726 std::istringstream tmp_is2(tmp_os.str());
727 m_nodedef->deSerialize(tmp_is2);
728 m_nodedef_received = true;
731 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
733 infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
736 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
738 infostream << "Client: Received item definitions: packet size: "
739 << pkt->getSize() << std::endl;
741 // Mesh update thread must be stopped while
742 // updating content definitions
743 sanity_check(!m_mesh_update_thread.IsRunning());
745 // Decompress item definitions
746 std::string datastring(pkt->getString(0), pkt->getSize());
747 std::istringstream is(datastring, std::ios_base::binary);
748 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
749 std::ostringstream tmp_os;
750 decompressZlib(tmp_is, tmp_os);
752 // Deserialize node definitions
753 std::istringstream tmp_is2(tmp_os.str());
754 m_itemdef->deSerialize(tmp_is2);
755 m_itemdef_received = true;
758 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
763 u8 type; // 0=local, 1=positional, 2=object
768 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
774 client_id = m_sound->playSound(name, loop, gain);
776 case 1: // positional
777 client_id = m_sound->playSoundAt(name, loop, gain, pos);
781 ClientActiveObject *cao = m_env.getActiveObject(object_id);
783 pos = cao->getPosition();
784 client_id = m_sound->playSoundAt(name, loop, gain, pos);
785 // TODO: Set up sound to move with object
792 if (client_id != -1) {
793 m_sounds_server_to_client[server_id] = client_id;
794 m_sounds_client_to_server[client_id] = server_id;
796 m_sounds_to_objects[client_id] = object_id;
800 void Client::handleCommand_StopSound(NetworkPacket* pkt)
806 std::map<s32, int>::iterator i =
807 m_sounds_server_to_client.find(server_id);
809 if (i != m_sounds_server_to_client.end()) {
810 int client_id = i->second;
811 m_sound->stopSound(client_id);
815 void Client::handleCommand_Privileges(NetworkPacket* pkt)
817 m_privileges.clear();
818 infostream << "Client: Privileges updated: ";
821 *pkt >> num_privileges;
823 for (u16 i = 0; i < num_privileges; i++) {
828 m_privileges.insert(priv);
829 infostream << priv << " ";
831 infostream << std::endl;
834 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
836 Player *player = m_env.getLocalPlayer();
837 assert(player != NULL);
839 // Store formspec in LocalPlayer
840 player->inventory_formspec = pkt->readLongString();
843 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
845 std::string datastring(pkt->getString(0), pkt->getSize());
846 std::istringstream is(datastring, std::ios_base::binary);
848 std::string name = deSerializeString(is);
850 infostream << "Client: Detached inventory update: \"" << name
851 << "\"" << std::endl;
853 Inventory *inv = NULL;
854 if (m_detached_inventories.count(name) > 0)
855 inv = m_detached_inventories[name];
857 inv = new Inventory(m_itemdef);
858 m_detached_inventories[name] = inv;
860 inv->deSerialize(is);
863 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
865 std::string formspec = pkt->readLongString();
866 std::string formname;
871 event.type = CE_SHOW_FORMSPEC;
872 // pointer is required as event is a struct only!
873 // adding a std:string to a struct isn't possible
874 event.show_formspec.formspec = new std::string(formspec);
875 event.show_formspec.formname = new std::string(formname);
876 m_client_event_queue.push(event);
879 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
881 std::string datastring(pkt->getString(0), pkt->getSize());
882 std::istringstream is(datastring, std::ios_base::binary);
884 v3f pos = readV3F1000(is);
885 v3f vel = readV3F1000(is);
886 v3f acc = readV3F1000(is);
887 float expirationtime = readF1000(is);
888 float size = readF1000(is);
889 bool collisiondetection = readU8(is);
890 std::string texture = deSerializeLongString(is);
891 bool vertical = false;
893 vertical = readU8(is);
897 event.type = CE_SPAWN_PARTICLE;
898 event.spawn_particle.pos = new v3f (pos);
899 event.spawn_particle.vel = new v3f (vel);
900 event.spawn_particle.acc = new v3f (acc);
901 event.spawn_particle.expirationtime = expirationtime;
902 event.spawn_particle.size = size;
903 event.spawn_particle.collisiondetection = collisiondetection;
904 event.spawn_particle.vertical = vertical;
905 event.spawn_particle.texture = new std::string(texture);
907 m_client_event_queue.push(event);
910 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
924 bool collisiondetection;
927 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
928 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
929 >> maxsize >> collisiondetection;
931 std::string texture = pkt->readLongString();
935 bool vertical = false;
941 event.type = CE_ADD_PARTICLESPAWNER;
942 event.add_particlespawner.amount = amount;
943 event.add_particlespawner.spawntime = spawntime;
944 event.add_particlespawner.minpos = new v3f (minpos);
945 event.add_particlespawner.maxpos = new v3f (maxpos);
946 event.add_particlespawner.minvel = new v3f (minvel);
947 event.add_particlespawner.maxvel = new v3f (maxvel);
948 event.add_particlespawner.minacc = new v3f (minacc);
949 event.add_particlespawner.maxacc = new v3f (maxacc);
950 event.add_particlespawner.minexptime = minexptime;
951 event.add_particlespawner.maxexptime = maxexptime;
952 event.add_particlespawner.minsize = minsize;
953 event.add_particlespawner.maxsize = maxsize;
954 event.add_particlespawner.collisiondetection = collisiondetection;
955 event.add_particlespawner.vertical = vertical;
956 event.add_particlespawner.texture = new std::string(texture);
957 event.add_particlespawner.id = id;
959 m_client_event_queue.push(event);
963 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
968 // Modification set 13/03/15, 1 year of compat for protocol v24
969 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
978 event.type = CE_DELETE_PARTICLESPAWNER;
979 event.delete_particlespawner.id =
980 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
982 m_client_event_queue.push(event);
985 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
987 std::string datastring(pkt->getString(0), pkt->getSize());
988 std::istringstream is(datastring, std::ios_base::binary);
1004 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
1005 >> dir >> align >> offset;
1009 catch(SerializationError &e) {};
1013 } catch(SerializationError &e) {};
1016 event.type = CE_HUDADD;
1017 event.hudadd.id = id;
1018 event.hudadd.type = type;
1019 event.hudadd.pos = new v2f(pos);
1020 event.hudadd.name = new std::string(name);
1021 event.hudadd.scale = new v2f(scale);
1022 event.hudadd.text = new std::string(text);
1023 event.hudadd.number = number;
1024 event.hudadd.item = item;
1025 event.hudadd.dir = dir;
1026 event.hudadd.align = new v2f(align);
1027 event.hudadd.offset = new v2f(offset);
1028 event.hudadd.world_pos = new v3f(world_pos);
1029 event.hudadd.size = new v2s32(size);
1030 m_client_event_queue.push(event);
1033 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1040 event.type = CE_HUDRM;
1041 event.hudrm.id = id;
1042 m_client_event_queue.push(event);
1045 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1057 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1058 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1060 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1062 else if (stat == HUD_STAT_WORLD_POS)
1064 else if (stat == HUD_STAT_SIZE )
1070 event.type = CE_HUDCHANGE;
1071 event.hudchange.id = id;
1072 event.hudchange.stat = (HudElementStat)stat;
1073 event.hudchange.v2fdata = new v2f(v2fdata);
1074 event.hudchange.v3fdata = new v3f(v3fdata);
1075 event.hudchange.sdata = new std::string(sdata);
1076 event.hudchange.data = intdata;
1077 event.hudchange.v2s32data = new v2s32(v2s32data);
1078 m_client_event_queue.push(event);
1081 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1085 *pkt >> flags >> mask;
1087 Player *player = m_env.getLocalPlayer();
1088 assert(player != NULL);
1090 player->hud_flags &= ~mask;
1091 player->hud_flags |= flags;
1094 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1096 u16 param; std::string value;
1098 *pkt >> param >> value;
1100 Player *player = m_env.getLocalPlayer();
1101 assert(player != NULL);
1103 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1104 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1105 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1106 player->hud_hotbar_itemcount = hotbar_itemcount;
1108 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1109 ((LocalPlayer *) player)->hotbar_image = value;
1111 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1112 ((LocalPlayer *) player)->hotbar_selected_image = value;
1116 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1118 std::string datastring(pkt->getString(0), pkt->getSize());
1119 std::istringstream is(datastring, std::ios_base::binary);
1121 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1122 std::string *type = new std::string(deSerializeString(is));
1123 u16 count = readU16(is);
1124 std::vector<std::string> *params = new std::vector<std::string>;
1126 for (size_t i = 0; i < count; i++)
1127 params->push_back(deSerializeString(is));
1130 event.type = CE_SET_SKY;
1131 event.set_sky.bgcolor = bgcolor;
1132 event.set_sky.type = type;
1133 event.set_sky.params = params;
1134 m_client_event_queue.push(event);
1137 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1140 u16 day_night_ratio_u;
1142 *pkt >> do_override >> day_night_ratio_u;
1144 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1147 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1148 event.override_day_night_ratio.do_override = do_override;
1149 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1150 m_client_event_queue.push(event);
1153 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1155 LocalPlayer *player = m_env.getLocalPlayer();
1156 assert(player != NULL);
1158 *pkt >> player->local_animations[0];
1159 *pkt >> player->local_animations[1];
1160 *pkt >> player->local_animations[2];
1161 *pkt >> player->local_animations[3];
1162 *pkt >> player->local_animation_speed;
1165 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1167 LocalPlayer *player = m_env.getLocalPlayer();
1168 assert(player != NULL);
1170 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1173 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1175 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1176 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1177 errorstream << "Client: Recieved SRP S_B login message,"
1178 << " but wasn't supposed to (chosen_mech="
1179 << m_chosen_auth_mech << ")." << std::endl;
1185 SRPUser *usr = (SRPUser *) m_auth_data;
1190 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1192 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1193 (const unsigned char *) B.c_str(), B.size(),
1194 (unsigned char **) &bytes_M, &len_M);
1197 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1201 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1202 resp_pkt << std::string(bytes_M, len_M);