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)
452 std::string datastring(pkt->getString(0), pkt->getSize());
453 std::istringstream is(datastring, std::ios_base::binary);
457 u16 id = readU16(is);
461 std::string message = deSerializeString(is);
463 // Pass on to the environment
464 m_env.processActiveObjectMessage(id, message);
466 } catch (SerializationError &e) {
467 errorstream << "Client::handleCommand_ActiveObjectMessages: "
468 << "caught SerializationError: " << e.what() << std::endl;
472 void Client::handleCommand_Movement(NetworkPacket* pkt)
474 Player *player = m_env.getLocalPlayer();
475 assert(player != NULL);
477 float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
479 *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
480 >> lf >> lfs >> ls >> g;
482 player->movement_acceleration_default = mad * BS;
483 player->movement_acceleration_air = maa * BS;
484 player->movement_acceleration_fast = maf * BS;
485 player->movement_speed_walk = msw * BS;
486 player->movement_speed_crouch = mscr * BS;
487 player->movement_speed_fast = msf * BS;
488 player->movement_speed_climb = mscl * BS;
489 player->movement_speed_jump = msj * BS;
490 player->movement_liquid_fluidity = lf * BS;
491 player->movement_liquid_fluidity_smooth = lfs * BS;
492 player->movement_liquid_sink = ls * BS;
493 player->movement_gravity = g * BS;
496 void Client::handleCommand_HP(NetworkPacket* pkt)
499 Player *player = m_env.getLocalPlayer();
500 assert(player != NULL);
502 u8 oldhp = player->hp;
510 // Add to ClientEvent queue
512 event.type = CE_PLAYER_DAMAGE;
513 event.player_damage.amount = oldhp - hp;
514 m_client_event_queue.push(event);
518 void Client::handleCommand_Breath(NetworkPacket* pkt)
520 Player *player = m_env.getLocalPlayer();
521 assert(player != NULL);
527 player->setBreath(breath);
530 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
532 Player *player = m_env.getLocalPlayer();
533 assert(player != NULL);
538 *pkt >> pos >> pitch >> yaw;
540 player->setPosition(pos);
542 infostream << "Client got TOCLIENT_MOVE_PLAYER"
543 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
544 << " pitch=" << pitch
549 Add to ClientEvent queue.
550 This has to be sent to the main program because otherwise
551 it would just force the pitch and yaw values to whatever
552 the camera points to.
555 event.type = CE_PLAYER_FORCE_MOVE;
556 event.player_force_move.pitch = pitch;
557 event.player_force_move.yaw = yaw;
558 m_client_event_queue.push(event);
560 // Ignore damage for a few seconds, so that the player doesn't
561 // get damage from falling on ground
562 m_ignore_damage_timer = 3.0;
565 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
567 infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
570 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
572 bool set_camera_point_target;
573 v3f camera_point_target;
575 *pkt >> set_camera_point_target;
576 *pkt >> camera_point_target;
579 event.type = CE_DEATHSCREEN;
580 event.deathscreen.set_camera_point_target = set_camera_point_target;
581 event.deathscreen.camera_point_target_x = camera_point_target.X;
582 event.deathscreen.camera_point_target_y = camera_point_target.Y;
583 event.deathscreen.camera_point_target_z = camera_point_target.Z;
584 m_client_event_queue.push(event);
587 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
593 infostream << "Client: Received media announcement: packet size: "
594 << pkt->getSize() << std::endl;
596 if (m_media_downloader == NULL ||
597 m_media_downloader->isStarted()) {
598 const char *problem = m_media_downloader ?
599 "we already saw another announcement" :
600 "all media has been received already";
601 errorstream << "Client: Received media announcement but "
603 << " files=" << num_files
604 << " size=" << pkt->getSize() << std::endl;
608 // Mesh update thread must be stopped while
609 // updating content definitions
610 sanity_check(!m_mesh_update_thread.IsRunning());
612 for (u16 i = 0; i < num_files; i++) {
613 std::string name, sha1_base64;
615 *pkt >> name >> sha1_base64;
617 std::string sha1_raw = base64_decode(sha1_base64);
618 m_media_downloader->addFile(name, sha1_raw);
621 std::vector<std::string> remote_media;
629 std::string baseurl = trim(sf.next(","));
631 m_media_downloader->addRemoteServer(baseurl);
634 catch(SerializationError& e) {
635 // not supported by server or turned off
638 m_media_downloader->step(this);
641 void Client::handleCommand_Media(NetworkPacket* pkt)
645 u16 total number of file bunches
646 u16 index of this bunch
647 u32 number of files in this bunch
659 *pkt >> num_bunches >> bunch_i >> num_files;
661 infostream << "Client: Received files: bunch " << bunch_i << "/"
662 << num_bunches << " files=" << num_files
663 << " size=" << pkt->getSize() << std::endl;
668 if (m_media_downloader == NULL ||
669 !m_media_downloader->isStarted()) {
670 const char *problem = m_media_downloader ?
671 "media has not been requested" :
672 "all media has been received already";
673 errorstream << "Client: Received media but "
675 << " bunch " << bunch_i << "/" << num_bunches
676 << " files=" << num_files
677 << " size=" << pkt->getSize() << std::endl;
681 // Mesh update thread must be stopped while
682 // updating content definitions
683 sanity_check(!m_mesh_update_thread.IsRunning());
685 for (u32 i=0; i < num_files; i++) {
690 std::string data = pkt->readLongString();
692 m_media_downloader->conventionalTransferDone(
697 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
699 infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl;
702 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
704 infostream << "Client: Received node definitions: packet size: "
705 << pkt->getSize() << std::endl;
707 // Mesh update thread must be stopped while
708 // updating content definitions
709 sanity_check(!m_mesh_update_thread.IsRunning());
711 // Decompress node definitions
712 std::string datastring(pkt->getString(0), pkt->getSize());
713 std::istringstream is(datastring, std::ios_base::binary);
714 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
715 std::ostringstream tmp_os;
716 decompressZlib(tmp_is, tmp_os);
718 // Deserialize node definitions
719 std::istringstream tmp_is2(tmp_os.str());
720 m_nodedef->deSerialize(tmp_is2);
721 m_nodedef_received = true;
724 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
726 infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
729 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
731 infostream << "Client: Received item definitions: packet size: "
732 << pkt->getSize() << std::endl;
734 // Mesh update thread must be stopped while
735 // updating content definitions
736 sanity_check(!m_mesh_update_thread.IsRunning());
738 // Decompress item definitions
739 std::string datastring(pkt->getString(0), pkt->getSize());
740 std::istringstream is(datastring, std::ios_base::binary);
741 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
742 std::ostringstream tmp_os;
743 decompressZlib(tmp_is, tmp_os);
745 // Deserialize node definitions
746 std::istringstream tmp_is2(tmp_os.str());
747 m_itemdef->deSerialize(tmp_is2);
748 m_itemdef_received = true;
751 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
756 u8 type; // 0=local, 1=positional, 2=object
761 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
767 client_id = m_sound->playSound(name, loop, gain);
769 case 1: // positional
770 client_id = m_sound->playSoundAt(name, loop, gain, pos);
774 ClientActiveObject *cao = m_env.getActiveObject(object_id);
776 pos = cao->getPosition();
777 client_id = m_sound->playSoundAt(name, loop, gain, pos);
778 // TODO: Set up sound to move with object
785 if (client_id != -1) {
786 m_sounds_server_to_client[server_id] = client_id;
787 m_sounds_client_to_server[client_id] = server_id;
789 m_sounds_to_objects[client_id] = object_id;
793 void Client::handleCommand_StopSound(NetworkPacket* pkt)
799 std::map<s32, int>::iterator i =
800 m_sounds_server_to_client.find(server_id);
802 if (i != m_sounds_server_to_client.end()) {
803 int client_id = i->second;
804 m_sound->stopSound(client_id);
808 void Client::handleCommand_Privileges(NetworkPacket* pkt)
810 m_privileges.clear();
811 infostream << "Client: Privileges updated: ";
814 *pkt >> num_privileges;
816 for (u16 i = 0; i < num_privileges; i++) {
821 m_privileges.insert(priv);
822 infostream << priv << " ";
824 infostream << std::endl;
827 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
829 Player *player = m_env.getLocalPlayer();
830 assert(player != NULL);
832 // Store formspec in LocalPlayer
833 player->inventory_formspec = pkt->readLongString();
836 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
838 std::string datastring(pkt->getString(0), pkt->getSize());
839 std::istringstream is(datastring, std::ios_base::binary);
841 std::string name = deSerializeString(is);
843 infostream << "Client: Detached inventory update: \"" << name
844 << "\"" << std::endl;
846 Inventory *inv = NULL;
847 if (m_detached_inventories.count(name) > 0)
848 inv = m_detached_inventories[name];
850 inv = new Inventory(m_itemdef);
851 m_detached_inventories[name] = inv;
853 inv->deSerialize(is);
856 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
858 std::string formspec = pkt->readLongString();
859 std::string formname;
864 event.type = CE_SHOW_FORMSPEC;
865 // pointer is required as event is a struct only!
866 // adding a std:string to a struct isn't possible
867 event.show_formspec.formspec = new std::string(formspec);
868 event.show_formspec.formname = new std::string(formname);
869 m_client_event_queue.push(event);
872 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
874 std::string datastring(pkt->getString(0), pkt->getSize());
875 std::istringstream is(datastring, std::ios_base::binary);
877 v3f pos = readV3F1000(is);
878 v3f vel = readV3F1000(is);
879 v3f acc = readV3F1000(is);
880 float expirationtime = readF1000(is);
881 float size = readF1000(is);
882 bool collisiondetection = readU8(is);
883 std::string texture = deSerializeLongString(is);
884 bool vertical = false;
886 vertical = readU8(is);
890 event.type = CE_SPAWN_PARTICLE;
891 event.spawn_particle.pos = new v3f (pos);
892 event.spawn_particle.vel = new v3f (vel);
893 event.spawn_particle.acc = new v3f (acc);
894 event.spawn_particle.expirationtime = expirationtime;
895 event.spawn_particle.size = size;
896 event.spawn_particle.collisiondetection = collisiondetection;
897 event.spawn_particle.vertical = vertical;
898 event.spawn_particle.texture = new std::string(texture);
900 m_client_event_queue.push(event);
903 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
917 bool collisiondetection;
920 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
921 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
922 >> maxsize >> collisiondetection;
924 std::string texture = pkt->readLongString();
928 bool vertical = false;
934 event.type = CE_ADD_PARTICLESPAWNER;
935 event.add_particlespawner.amount = amount;
936 event.add_particlespawner.spawntime = spawntime;
937 event.add_particlespawner.minpos = new v3f (minpos);
938 event.add_particlespawner.maxpos = new v3f (maxpos);
939 event.add_particlespawner.minvel = new v3f (minvel);
940 event.add_particlespawner.maxvel = new v3f (maxvel);
941 event.add_particlespawner.minacc = new v3f (minacc);
942 event.add_particlespawner.maxacc = new v3f (maxacc);
943 event.add_particlespawner.minexptime = minexptime;
944 event.add_particlespawner.maxexptime = maxexptime;
945 event.add_particlespawner.minsize = minsize;
946 event.add_particlespawner.maxsize = maxsize;
947 event.add_particlespawner.collisiondetection = collisiondetection;
948 event.add_particlespawner.vertical = vertical;
949 event.add_particlespawner.texture = new std::string(texture);
950 event.add_particlespawner.id = id;
952 m_client_event_queue.push(event);
956 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
961 // Modification set 13/03/15, 1 year of compat for protocol v24
962 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
971 event.type = CE_DELETE_PARTICLESPAWNER;
972 event.delete_particlespawner.id =
973 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
975 m_client_event_queue.push(event);
978 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
980 std::string datastring(pkt->getString(0), pkt->getSize());
981 std::istringstream is(datastring, std::ios_base::binary);
997 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
998 >> dir >> align >> offset;
1002 catch(SerializationError &e) {};
1006 } catch(SerializationError &e) {};
1009 event.type = CE_HUDADD;
1010 event.hudadd.id = id;
1011 event.hudadd.type = type;
1012 event.hudadd.pos = new v2f(pos);
1013 event.hudadd.name = new std::string(name);
1014 event.hudadd.scale = new v2f(scale);
1015 event.hudadd.text = new std::string(text);
1016 event.hudadd.number = number;
1017 event.hudadd.item = item;
1018 event.hudadd.dir = dir;
1019 event.hudadd.align = new v2f(align);
1020 event.hudadd.offset = new v2f(offset);
1021 event.hudadd.world_pos = new v3f(world_pos);
1022 event.hudadd.size = new v2s32(size);
1023 m_client_event_queue.push(event);
1026 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1033 event.type = CE_HUDRM;
1034 event.hudrm.id = id;
1035 m_client_event_queue.push(event);
1038 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1050 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1051 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1053 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1055 else if (stat == HUD_STAT_WORLD_POS)
1057 else if (stat == HUD_STAT_SIZE )
1063 event.type = CE_HUDCHANGE;
1064 event.hudchange.id = id;
1065 event.hudchange.stat = (HudElementStat)stat;
1066 event.hudchange.v2fdata = new v2f(v2fdata);
1067 event.hudchange.v3fdata = new v3f(v3fdata);
1068 event.hudchange.sdata = new std::string(sdata);
1069 event.hudchange.data = intdata;
1070 event.hudchange.v2s32data = new v2s32(v2s32data);
1071 m_client_event_queue.push(event);
1074 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1078 *pkt >> flags >> mask;
1080 Player *player = m_env.getLocalPlayer();
1081 assert(player != NULL);
1083 player->hud_flags &= ~mask;
1084 player->hud_flags |= flags;
1087 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1089 u16 param; std::string value;
1091 *pkt >> param >> value;
1093 Player *player = m_env.getLocalPlayer();
1094 assert(player != NULL);
1096 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1097 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1098 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1099 player->hud_hotbar_itemcount = hotbar_itemcount;
1101 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1102 ((LocalPlayer *) player)->hotbar_image = value;
1104 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1105 ((LocalPlayer *) player)->hotbar_selected_image = value;
1109 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1111 std::string datastring(pkt->getString(0), pkt->getSize());
1112 std::istringstream is(datastring, std::ios_base::binary);
1114 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1115 std::string *type = new std::string(deSerializeString(is));
1116 u16 count = readU16(is);
1117 std::vector<std::string> *params = new std::vector<std::string>;
1119 for (size_t i = 0; i < count; i++)
1120 params->push_back(deSerializeString(is));
1123 event.type = CE_SET_SKY;
1124 event.set_sky.bgcolor = bgcolor;
1125 event.set_sky.type = type;
1126 event.set_sky.params = params;
1127 m_client_event_queue.push(event);
1130 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1133 u16 day_night_ratio_u;
1135 *pkt >> do_override >> day_night_ratio_u;
1137 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1140 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1141 event.override_day_night_ratio.do_override = do_override;
1142 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1143 m_client_event_queue.push(event);
1146 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1148 LocalPlayer *player = m_env.getLocalPlayer();
1149 assert(player != NULL);
1151 *pkt >> player->local_animations[0];
1152 *pkt >> player->local_animations[1];
1153 *pkt >> player->local_animations[2];
1154 *pkt >> player->local_animations[3];
1155 *pkt >> player->local_animation_speed;
1158 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1160 LocalPlayer *player = m_env.getLocalPlayer();
1161 assert(player != NULL);
1163 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1166 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1168 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1169 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1170 errorstream << "Client: Recieved SRP S_B login message,"
1171 << " but wasn't supposed to (chosen_mech="
1172 << m_chosen_auth_mech << ")." << std::endl;
1178 SRPUser *usr = (SRPUser *) m_auth_data;
1183 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1185 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1186 (const unsigned char *) B.c_str(), B.size(),
1187 (unsigned char **) &bytes_M, &len_M);
1190 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1194 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1195 resp_pkt << std::string(bytes_M, len_M);