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 received 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)
155 *pkt >> server_ser_ver;
157 infostream << "Client: TOCLIENT_INIT_LEGACY received with "
158 "server_ser_ver=" << ((int)server_ser_ver & 0xff) << std::endl;
160 if (!ser_ver_supported(server_ser_ver)) {
161 infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent "
162 << "unsupported ser_fmt_ver"<< std::endl;
166 m_server_ser_ver = server_ser_ver;
168 // We can be totally wrong with this guess
169 // but we only need some value < 25.
172 // Get player position
173 v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0);
174 if (pkt->getSize() >= 1 + 6) {
175 *pkt >> playerpos_s16;
177 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0);
180 // Set player position
181 Player *player = m_env.getLocalPlayer();
182 assert(player != NULL);
183 player->setPosition(playerpos_f);
185 if (pkt->getSize() >= 1 + 6 + 8) {
188 infostream << "Client: received map seed: " << m_map_seed << std::endl;
191 if (pkt->getSize() >= 1 + 6 + 8 + 4) {
192 *pkt >> m_recommended_send_interval;
193 infostream << "Client: received recommended send interval "
194 << m_recommended_send_interval<<std::endl;
198 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
204 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
206 // The server didn't like our password. Note, this needs
207 // to be processed even if the serialisation format has
208 // not been agreed yet, the same as TOCLIENT_INIT.
209 m_access_denied = true;
210 m_access_denied_reason = "Unknown";
212 if (pkt->getCommand() == TOCLIENT_ACCESS_DENIED) {
213 if (pkt->getSize() < 1)
216 u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
218 if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
219 *pkt >> m_access_denied_reason;
221 else if (denyCode < SERVER_ACCESSDENIED_MAX) {
222 m_access_denied_reason = accessDeniedStrings[denyCode];
225 // 13/03/15 Legacy code from 0.4.12 and lesser. must stay 1 year
226 // for compat with old clients
228 if (pkt->getSize() >= 2) {
229 std::wstring wide_reason;
231 m_access_denied_reason = wide_to_utf8(wide_reason);
236 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
238 if (pkt->getSize() < 6)
246 void Client::handleCommand_AddNode(NetworkPacket* pkt)
248 if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
255 n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
257 bool remove_metadata = true;
258 u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
259 if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
260 remove_metadata = false;
263 addNode(p, n, remove_metadata);
265 void Client::handleCommand_BlockData(NetworkPacket* pkt)
267 // Ignore too small packet
268 if (pkt->getSize() < 6)
274 std::string datastring(pkt->getString(6), pkt->getSize() - 6);
275 std::istringstream istr(datastring, std::ios_base::binary);
281 sector = m_env.getMap().emergeSector(p2d);
283 assert(sector->getPos() == p2d);
285 block = sector->getBlockNoCreateNoEx(p.Y);
288 Update an existing block
290 block->deSerialize(istr, m_server_ser_ver, false);
291 block->deSerializeNetworkSpecific(istr);
297 block = new MapBlock(&m_env.getMap(), p, this);
298 block->deSerialize(istr, m_server_ser_ver, false);
299 block->deSerializeNetworkSpecific(istr);
300 sector->insertBlock(block);
304 ServerMap::saveBlock(block, m_localdb);
308 Add it to mesh update queue and set it to be acknowledged after update.
310 addUpdateMeshTaskWithEdge(p, true);
313 void Client::handleCommand_Inventory(NetworkPacket* pkt)
315 if (pkt->getSize() < 1)
318 std::string datastring(pkt->getString(0), pkt->getSize());
319 std::istringstream is(datastring, std::ios_base::binary);
321 Player *player = m_env.getLocalPlayer();
322 assert(player != NULL);
324 player->inventory.deSerialize(is);
326 m_inventory_updated = true;
328 delete m_inventory_from_server;
329 m_inventory_from_server = new Inventory(player->inventory);
330 m_inventory_from_server_age = 0.0;
333 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
335 if (pkt->getSize() < 2)
342 time_of_day = time_of_day % 24000;
343 float time_speed = 0;
345 if (pkt->getSize() >= 2 + 4) {
349 // Old message; try to approximate speed of time by ourselves
350 float time_of_day_f = (float)time_of_day / 24000.0;
351 float tod_diff_f = 0;
353 if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
354 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
356 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
358 m_last_time_of_day_f = time_of_day_f;
359 float time_diff = m_time_of_day_update_timer;
360 m_time_of_day_update_timer = 0;
362 if (m_time_of_day_set) {
363 time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff;
364 infostream << "Client: Measured time_of_day speed (old format): "
365 << time_speed << " tod_diff_f=" << tod_diff_f
366 << " time_diff=" << time_diff << std::endl;
370 // Update environment
371 m_env.setTimeOfDay(time_of_day);
372 m_env.setTimeOfDaySpeed(time_speed);
373 m_time_of_day_set = true;
375 u32 dr = m_env.getDayNightRatio();
376 infostream << "Client: time_of_day=" << time_of_day
377 << " time_speed=" << time_speed
378 << " dr=" << dr << std::endl;
381 void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
392 std::wstring message;
393 for (u32 i = 0; i < len; i++) {
395 message += (wchar_t)read_wchar;
398 m_chat_queue.push(message);
401 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
404 u16 count of removed objects
405 for all removed objects {
408 u16 count of added objects
409 for all added objects {
412 u32 initialization data length
413 string initialization data
419 u16 removed_count, added_count, id;
421 // Read removed objects
422 *pkt >> removed_count;
424 for (u16 i = 0; i < removed_count; i++) {
426 m_env.removeActiveObject(id);
429 // Read added objects
432 for (u16 i = 0; i < added_count; i++) {
434 m_env.addActiveObject(id, type, pkt->readLongString());
436 } catch (PacketError &e) {
437 infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
438 << ". The packet is unreliable, ignoring" << std::endl;
442 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
453 // Get all data except the command number
454 std::string datastring(pkt->getString(0), pkt->getSize());
455 // Throw them in an istringstream
456 std::istringstream is(datastring, std::ios_base::binary);
459 while(is.eof() == false) {
461 u16 id = readU16((u8*)buf);
465 size_t message_size = readU16((u8*)buf);
467 message.reserve(message_size);
468 for (u32 i = 0; i < message_size; i++) {
470 message.append(buf, 1);
472 // Pass on to the environment
473 m_env.processActiveObjectMessage(id, message);
475 // Packet could be unreliable then ignore it
476 } catch (PacketError &e) {
477 infostream << "handleCommand_ActiveObjectMessages: " << e.what()
478 << ". The packet is unreliable, ignoring" << std::endl;
482 void Client::handleCommand_Movement(NetworkPacket* pkt)
484 Player *player = m_env.getLocalPlayer();
485 assert(player != NULL);
487 float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
489 *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
490 >> lf >> lfs >> ls >> g;
492 player->movement_acceleration_default = mad * BS;
493 player->movement_acceleration_air = maa * BS;
494 player->movement_acceleration_fast = maf * BS;
495 player->movement_speed_walk = msw * BS;
496 player->movement_speed_crouch = mscr * BS;
497 player->movement_speed_fast = msf * BS;
498 player->movement_speed_climb = mscl * BS;
499 player->movement_speed_jump = msj * BS;
500 player->movement_liquid_fluidity = lf * BS;
501 player->movement_liquid_fluidity_smooth = lfs * BS;
502 player->movement_liquid_sink = ls * BS;
503 player->movement_gravity = g * BS;
506 void Client::handleCommand_HP(NetworkPacket* pkt)
509 Player *player = m_env.getLocalPlayer();
510 assert(player != NULL);
512 u8 oldhp = player->hp;
520 // Add to ClientEvent queue
522 event.type = CE_PLAYER_DAMAGE;
523 event.player_damage.amount = oldhp - hp;
524 m_client_event_queue.push(event);
528 void Client::handleCommand_Breath(NetworkPacket* pkt)
530 Player *player = m_env.getLocalPlayer();
531 assert(player != NULL);
537 player->setBreath(breath);
540 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
542 Player *player = m_env.getLocalPlayer();
543 assert(player != NULL);
548 *pkt >> pos >> pitch >> yaw;
550 player->setPosition(pos);
552 infostream << "Client got TOCLIENT_MOVE_PLAYER"
553 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
554 << " pitch=" << pitch
559 Add to ClientEvent queue.
560 This has to be sent to the main program because otherwise
561 it would just force the pitch and yaw values to whatever
562 the camera points to.
565 event.type = CE_PLAYER_FORCE_MOVE;
566 event.player_force_move.pitch = pitch;
567 event.player_force_move.yaw = yaw;
568 m_client_event_queue.push(event);
570 // Ignore damage for a few seconds, so that the player doesn't
571 // get damage from falling on ground
572 m_ignore_damage_timer = 3.0;
575 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
577 infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
580 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
582 bool set_camera_point_target;
583 v3f camera_point_target;
585 *pkt >> set_camera_point_target;
586 *pkt >> camera_point_target;
589 event.type = CE_DEATHSCREEN;
590 event.deathscreen.set_camera_point_target = set_camera_point_target;
591 event.deathscreen.camera_point_target_x = camera_point_target.X;
592 event.deathscreen.camera_point_target_y = camera_point_target.Y;
593 event.deathscreen.camera_point_target_z = camera_point_target.Z;
594 m_client_event_queue.push(event);
597 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
603 infostream << "Client: Received media announcement: packet size: "
604 << pkt->getSize() << std::endl;
606 if (m_media_downloader == NULL ||
607 m_media_downloader->isStarted()) {
608 const char *problem = m_media_downloader ?
609 "we already saw another announcement" :
610 "all media has been received already";
611 errorstream << "Client: Received media announcement but "
613 << " files=" << num_files
614 << " size=" << pkt->getSize() << std::endl;
618 // Mesh update thread must be stopped while
619 // updating content definitions
620 sanity_check(!m_mesh_update_thread.IsRunning());
622 for (u16 i = 0; i < num_files; i++) {
623 std::string name, sha1_base64;
625 *pkt >> name >> sha1_base64;
627 std::string sha1_raw = base64_decode(sha1_base64);
628 m_media_downloader->addFile(name, sha1_raw);
631 std::vector<std::string> remote_media;
639 std::string baseurl = trim(sf.next(","));
641 m_media_downloader->addRemoteServer(baseurl);
644 catch(SerializationError& e) {
645 // not supported by server or turned off
648 m_media_downloader->step(this);
651 void Client::handleCommand_Media(NetworkPacket* pkt)
655 u16 total number of file bunches
656 u16 index of this bunch
657 u32 number of files in this bunch
669 *pkt >> num_bunches >> bunch_i >> num_files;
671 infostream << "Client: Received files: bunch " << bunch_i << "/"
672 << num_bunches << " files=" << num_files
673 << " size=" << pkt->getSize() << std::endl;
678 if (m_media_downloader == NULL ||
679 !m_media_downloader->isStarted()) {
680 const char *problem = m_media_downloader ?
681 "media has not been requested" :
682 "all media has been received already";
683 errorstream << "Client: Received media but "
685 << " bunch " << bunch_i << "/" << num_bunches
686 << " files=" << num_files
687 << " size=" << pkt->getSize() << std::endl;
691 // Mesh update thread must be stopped while
692 // updating content definitions
693 sanity_check(!m_mesh_update_thread.IsRunning());
695 for (u32 i=0; i < num_files; i++) {
700 std::string data = pkt->readLongString();
702 m_media_downloader->conventionalTransferDone(
707 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
709 infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl;
712 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
714 infostream << "Client: Received node definitions: packet size: "
715 << pkt->getSize() << std::endl;
717 // Mesh update thread must be stopped while
718 // updating content definitions
719 sanity_check(!m_mesh_update_thread.IsRunning());
721 // Decompress node definitions
722 std::string datastring(pkt->getString(0), pkt->getSize());
723 std::istringstream is(datastring, std::ios_base::binary);
724 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
725 std::ostringstream tmp_os;
726 decompressZlib(tmp_is, tmp_os);
728 // Deserialize node definitions
729 std::istringstream tmp_is2(tmp_os.str());
730 m_nodedef->deSerialize(tmp_is2);
731 m_nodedef_received = true;
734 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
736 infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
739 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
741 infostream << "Client: Received item definitions: packet size: "
742 << pkt->getSize() << std::endl;
744 // Mesh update thread must be stopped while
745 // updating content definitions
746 sanity_check(!m_mesh_update_thread.IsRunning());
748 // Decompress item definitions
749 std::string datastring(pkt->getString(0), pkt->getSize());
750 std::istringstream is(datastring, std::ios_base::binary);
751 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
752 std::ostringstream tmp_os;
753 decompressZlib(tmp_is, tmp_os);
755 // Deserialize node definitions
756 std::istringstream tmp_is2(tmp_os.str());
757 m_itemdef->deSerialize(tmp_is2);
758 m_itemdef_received = true;
761 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
766 u8 type; // 0=local, 1=positional, 2=object
771 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
777 client_id = m_sound->playSound(name, loop, gain);
779 case 1: // positional
780 client_id = m_sound->playSoundAt(name, loop, gain, pos);
784 ClientActiveObject *cao = m_env.getActiveObject(object_id);
786 pos = cao->getPosition();
787 client_id = m_sound->playSoundAt(name, loop, gain, pos);
788 // TODO: Set up sound to move with object
795 if (client_id != -1) {
796 m_sounds_server_to_client[server_id] = client_id;
797 m_sounds_client_to_server[client_id] = server_id;
799 m_sounds_to_objects[client_id] = object_id;
803 void Client::handleCommand_StopSound(NetworkPacket* pkt)
809 std::map<s32, int>::iterator i =
810 m_sounds_server_to_client.find(server_id);
812 if (i != m_sounds_server_to_client.end()) {
813 int client_id = i->second;
814 m_sound->stopSound(client_id);
818 void Client::handleCommand_Privileges(NetworkPacket* pkt)
820 m_privileges.clear();
821 infostream << "Client: Privileges updated: ";
824 *pkt >> num_privileges;
826 for (u16 i = 0; i < num_privileges; i++) {
831 m_privileges.insert(priv);
832 infostream << priv << " ";
834 infostream << std::endl;
837 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
839 Player *player = m_env.getLocalPlayer();
840 assert(player != NULL);
842 // Store formspec in LocalPlayer
843 player->inventory_formspec = pkt->readLongString();
846 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
848 std::string datastring(pkt->getString(0), pkt->getSize());
849 std::istringstream is(datastring, std::ios_base::binary);
851 std::string name = deSerializeString(is);
853 infostream << "Client: Detached inventory update: \"" << name
854 << "\"" << std::endl;
856 Inventory *inv = NULL;
857 if (m_detached_inventories.count(name) > 0)
858 inv = m_detached_inventories[name];
860 inv = new Inventory(m_itemdef);
861 m_detached_inventories[name] = inv;
863 inv->deSerialize(is);
866 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
868 std::string formspec = pkt->readLongString();
869 std::string formname;
874 event.type = CE_SHOW_FORMSPEC;
875 // pointer is required as event is a struct only!
876 // adding a std:string to a struct isn't possible
877 event.show_formspec.formspec = new std::string(formspec);
878 event.show_formspec.formname = new std::string(formname);
879 m_client_event_queue.push(event);
882 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
884 std::string datastring(pkt->getString(0), pkt->getSize());
885 std::istringstream is(datastring, std::ios_base::binary);
887 v3f pos = readV3F1000(is);
888 v3f vel = readV3F1000(is);
889 v3f acc = readV3F1000(is);
890 float expirationtime = readF1000(is);
891 float size = readF1000(is);
892 bool collisiondetection = readU8(is);
893 std::string texture = deSerializeLongString(is);
894 bool vertical = false;
896 vertical = readU8(is);
900 event.type = CE_SPAWN_PARTICLE;
901 event.spawn_particle.pos = new v3f (pos);
902 event.spawn_particle.vel = new v3f (vel);
903 event.spawn_particle.acc = new v3f (acc);
904 event.spawn_particle.expirationtime = expirationtime;
905 event.spawn_particle.size = size;
906 event.spawn_particle.collisiondetection = collisiondetection;
907 event.spawn_particle.vertical = vertical;
908 event.spawn_particle.texture = new std::string(texture);
910 m_client_event_queue.push(event);
913 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
927 bool collisiondetection;
930 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
931 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
932 >> maxsize >> collisiondetection;
934 std::string texture = pkt->readLongString();
938 bool vertical = false;
944 event.type = CE_ADD_PARTICLESPAWNER;
945 event.add_particlespawner.amount = amount;
946 event.add_particlespawner.spawntime = spawntime;
947 event.add_particlespawner.minpos = new v3f (minpos);
948 event.add_particlespawner.maxpos = new v3f (maxpos);
949 event.add_particlespawner.minvel = new v3f (minvel);
950 event.add_particlespawner.maxvel = new v3f (maxvel);
951 event.add_particlespawner.minacc = new v3f (minacc);
952 event.add_particlespawner.maxacc = new v3f (maxacc);
953 event.add_particlespawner.minexptime = minexptime;
954 event.add_particlespawner.maxexptime = maxexptime;
955 event.add_particlespawner.minsize = minsize;
956 event.add_particlespawner.maxsize = maxsize;
957 event.add_particlespawner.collisiondetection = collisiondetection;
958 event.add_particlespawner.vertical = vertical;
959 event.add_particlespawner.texture = new std::string(texture);
960 event.add_particlespawner.id = id;
962 m_client_event_queue.push(event);
966 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
971 // Modification set 13/03/15, 1 year of compat for protocol v24
972 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
981 event.type = CE_DELETE_PARTICLESPAWNER;
982 event.delete_particlespawner.id =
983 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
985 m_client_event_queue.push(event);
988 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
990 std::string datastring(pkt->getString(0), pkt->getSize());
991 std::istringstream is(datastring, std::ios_base::binary);
1007 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
1008 >> dir >> align >> offset;
1012 catch(SerializationError &e) {};
1016 } catch(SerializationError &e) {};
1019 event.type = CE_HUDADD;
1020 event.hudadd.id = id;
1021 event.hudadd.type = type;
1022 event.hudadd.pos = new v2f(pos);
1023 event.hudadd.name = new std::string(name);
1024 event.hudadd.scale = new v2f(scale);
1025 event.hudadd.text = new std::string(text);
1026 event.hudadd.number = number;
1027 event.hudadd.item = item;
1028 event.hudadd.dir = dir;
1029 event.hudadd.align = new v2f(align);
1030 event.hudadd.offset = new v2f(offset);
1031 event.hudadd.world_pos = new v3f(world_pos);
1032 event.hudadd.size = new v2s32(size);
1033 m_client_event_queue.push(event);
1036 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1043 event.type = CE_HUDRM;
1044 event.hudrm.id = id;
1045 m_client_event_queue.push(event);
1048 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1060 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1061 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1063 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1065 else if (stat == HUD_STAT_WORLD_POS)
1067 else if (stat == HUD_STAT_SIZE )
1073 event.type = CE_HUDCHANGE;
1074 event.hudchange.id = id;
1075 event.hudchange.stat = (HudElementStat)stat;
1076 event.hudchange.v2fdata = new v2f(v2fdata);
1077 event.hudchange.v3fdata = new v3f(v3fdata);
1078 event.hudchange.sdata = new std::string(sdata);
1079 event.hudchange.data = intdata;
1080 event.hudchange.v2s32data = new v2s32(v2s32data);
1081 m_client_event_queue.push(event);
1084 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1088 *pkt >> flags >> mask;
1090 Player *player = m_env.getLocalPlayer();
1091 assert(player != NULL);
1093 player->hud_flags &= ~mask;
1094 player->hud_flags |= flags;
1097 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1099 u16 param; std::string value;
1101 *pkt >> param >> value;
1103 Player *player = m_env.getLocalPlayer();
1104 assert(player != NULL);
1106 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1107 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1108 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1109 player->hud_hotbar_itemcount = hotbar_itemcount;
1111 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1112 ((LocalPlayer *) player)->hotbar_image = value;
1114 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1115 ((LocalPlayer *) player)->hotbar_selected_image = value;
1119 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1121 std::string datastring(pkt->getString(0), pkt->getSize());
1122 std::istringstream is(datastring, std::ios_base::binary);
1124 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1125 std::string *type = new std::string(deSerializeString(is));
1126 u16 count = readU16(is);
1127 std::vector<std::string> *params = new std::vector<std::string>;
1129 for (size_t i = 0; i < count; i++)
1130 params->push_back(deSerializeString(is));
1133 event.type = CE_SET_SKY;
1134 event.set_sky.bgcolor = bgcolor;
1135 event.set_sky.type = type;
1136 event.set_sky.params = params;
1137 m_client_event_queue.push(event);
1140 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1143 u16 day_night_ratio_u;
1145 *pkt >> do_override >> day_night_ratio_u;
1147 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1150 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1151 event.override_day_night_ratio.do_override = do_override;
1152 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1153 m_client_event_queue.push(event);
1156 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1158 LocalPlayer *player = m_env.getLocalPlayer();
1159 assert(player != NULL);
1161 *pkt >> player->local_animations[0];
1162 *pkt >> player->local_animations[1];
1163 *pkt >> player->local_animations[2];
1164 *pkt >> player->local_animations[3];
1165 *pkt >> player->local_animation_speed;
1168 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1170 LocalPlayer *player = m_env.getLocalPlayer();
1171 assert(player != NULL);
1173 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1176 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1178 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1179 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1180 errorstream << "Client: Recieved SRP S_B login message,"
1181 << " but wasn't supposed to (chosen_mech="
1182 << m_chosen_auth_mech << ")." << std::endl;
1188 SRPUser *usr = (SRPUser *) m_auth_data;
1193 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1195 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1196 (const unsigned char *) B.c_str(), B.size(),
1197 (unsigned char **) &bytes_M, &len_M);
1200 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1204 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1205 resp_pkt << std::string(bytes_M, len_M);