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)
106 *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
107 >> m_sudo_auth_methods;
109 playerpos -= v3f(0, BS / 2, 0);
111 // Set player position
112 Player *player = m_env.getLocalPlayer();
113 assert(player != NULL);
114 player->setPosition(playerpos);
116 infostream << "Client: received map seed: " << m_map_seed << std::endl;
117 infostream << "Client: received recommended send interval "
118 << m_recommended_send_interval<<std::endl;
121 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
126 void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
130 m_password = m_new_password;
132 verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
134 // send packet to actually set the password
135 startAuth(AUTH_MECHANISM_FIRST_SRP);
138 m_chosen_auth_mech = AUTH_MECHANISM_NONE;
140 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
142 m_chat_queue.push(L"Password change denied. Password NOT changed.");
143 // reset everything and be sad
146 void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
148 if (pkt->getSize() < 1)
152 *pkt >> server_ser_ver;
154 infostream << "Client: TOCLIENT_INIT_LEGACY received with "
155 "server_ser_ver=" << ((int)server_ser_ver & 0xff) << std::endl;
157 if (!ser_ver_supported(server_ser_ver)) {
158 infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent "
159 << "unsupported ser_fmt_ver"<< std::endl;
163 m_server_ser_ver = server_ser_ver;
165 // We can be totally wrong with this guess
166 // but we only need some value < 25.
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_SHUTDOWN ||
216 denyCode == SERVER_ACCESSDENIED_CRASH) {
217 *pkt >> m_access_denied_reason;
218 if (m_access_denied_reason == "") {
219 m_access_denied_reason = accessDeniedStrings[denyCode];
223 m_access_denied_reconnect = reconnect & 1;
224 } else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
225 *pkt >> m_access_denied_reason;
226 } else if (denyCode < SERVER_ACCESSDENIED_MAX) {
227 m_access_denied_reason = accessDeniedStrings[denyCode];
229 // Allow us to add new error messages to the
230 // protocol without raising the protocol version, if we want to.
231 // Until then (which may be never), this is outside
232 // of the defined protocol.
233 *pkt >> m_access_denied_reason;
234 if (m_access_denied_reason == "") {
235 m_access_denied_reason = "Unknown";
239 // 13/03/15 Legacy code from 0.4.12 and lesser. must stay 1 year
240 // for compat with old clients
242 if (pkt->getSize() >= 2) {
243 std::wstring wide_reason;
245 m_access_denied_reason = wide_to_utf8(wide_reason);
250 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
252 if (pkt->getSize() < 6)
260 void Client::handleCommand_AddNode(NetworkPacket* pkt)
262 if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
269 n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
271 bool remove_metadata = true;
272 u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
273 if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
274 remove_metadata = false;
277 addNode(p, n, remove_metadata);
279 void Client::handleCommand_BlockData(NetworkPacket* pkt)
281 // Ignore too small packet
282 if (pkt->getSize() < 6)
288 std::string datastring(pkt->getString(6), pkt->getSize() - 6);
289 std::istringstream istr(datastring, std::ios_base::binary);
295 sector = m_env.getMap().emergeSector(p2d);
297 assert(sector->getPos() == p2d);
299 block = sector->getBlockNoCreateNoEx(p.Y);
302 Update an existing block
304 block->deSerialize(istr, m_server_ser_ver, false);
305 block->deSerializeNetworkSpecific(istr);
311 block = new MapBlock(&m_env.getMap(), p, this);
312 block->deSerialize(istr, m_server_ser_ver, false);
313 block->deSerializeNetworkSpecific(istr);
314 sector->insertBlock(block);
318 ServerMap::saveBlock(block, m_localdb);
322 Add it to mesh update queue and set it to be acknowledged after update.
324 addUpdateMeshTaskWithEdge(p, true);
327 void Client::handleCommand_Inventory(NetworkPacket* pkt)
329 if (pkt->getSize() < 1)
332 std::string datastring(pkt->getString(0), pkt->getSize());
333 std::istringstream is(datastring, std::ios_base::binary);
335 Player *player = m_env.getLocalPlayer();
336 assert(player != NULL);
338 player->inventory.deSerialize(is);
340 m_inventory_updated = true;
342 delete m_inventory_from_server;
343 m_inventory_from_server = new Inventory(player->inventory);
344 m_inventory_from_server_age = 0.0;
347 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
349 if (pkt->getSize() < 2)
356 time_of_day = time_of_day % 24000;
357 float time_speed = 0;
359 if (pkt->getSize() >= 2 + 4) {
363 // Old message; try to approximate speed of time by ourselves
364 float time_of_day_f = (float)time_of_day / 24000.0;
365 float tod_diff_f = 0;
367 if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
368 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
370 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
372 m_last_time_of_day_f = time_of_day_f;
373 float time_diff = m_time_of_day_update_timer;
374 m_time_of_day_update_timer = 0;
376 if (m_time_of_day_set) {
377 time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff;
378 infostream << "Client: Measured time_of_day speed (old format): "
379 << time_speed << " tod_diff_f=" << tod_diff_f
380 << " time_diff=" << time_diff << std::endl;
384 // Update environment
385 m_env.setTimeOfDay(time_of_day);
386 m_env.setTimeOfDaySpeed(time_speed);
387 m_time_of_day_set = true;
389 u32 dr = m_env.getDayNightRatio();
390 infostream << "Client: time_of_day=" << time_of_day
391 << " time_speed=" << time_speed
392 << " dr=" << dr << std::endl;
395 void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
406 std::wstring message;
407 for (u32 i = 0; i < len; i++) {
409 message += (wchar_t)read_wchar;
412 m_chat_queue.push(message);
415 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
418 u16 count of removed objects
419 for all removed objects {
422 u16 count of added objects
423 for all added objects {
426 u32 initialization data length
427 string initialization data
433 u16 removed_count, added_count, id;
435 // Read removed objects
436 *pkt >> removed_count;
438 for (u16 i = 0; i < removed_count; i++) {
440 m_env.removeActiveObject(id);
443 // Read added objects
446 for (u16 i = 0; i < added_count; i++) {
448 m_env.addActiveObject(id, type, pkt->readLongString());
450 } catch (PacketError &e) {
451 infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
452 << ". The packet is unreliable, ignoring" << std::endl;
456 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
466 std::string datastring(pkt->getString(0), pkt->getSize());
467 std::istringstream is(datastring, std::ios_base::binary);
471 u16 id = readU16(is);
475 std::string message = deSerializeString(is);
477 // Pass on to the environment
478 m_env.processActiveObjectMessage(id, message);
480 } catch (SerializationError &e) {
481 errorstream << "Client::handleCommand_ActiveObjectMessages: "
482 << "caught SerializationError: " << e.what() << std::endl;
486 void Client::handleCommand_Movement(NetworkPacket* pkt)
488 Player *player = m_env.getLocalPlayer();
489 assert(player != NULL);
491 float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
493 *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
494 >> lf >> lfs >> ls >> g;
496 player->movement_acceleration_default = mad * BS;
497 player->movement_acceleration_air = maa * BS;
498 player->movement_acceleration_fast = maf * BS;
499 player->movement_speed_walk = msw * BS;
500 player->movement_speed_crouch = mscr * BS;
501 player->movement_speed_fast = msf * BS;
502 player->movement_speed_climb = mscl * BS;
503 player->movement_speed_jump = msj * BS;
504 player->movement_liquid_fluidity = lf * BS;
505 player->movement_liquid_fluidity_smooth = lfs * BS;
506 player->movement_liquid_sink = ls * BS;
507 player->movement_gravity = g * BS;
510 void Client::handleCommand_HP(NetworkPacket* pkt)
513 Player *player = m_env.getLocalPlayer();
514 assert(player != NULL);
516 u8 oldhp = player->hp;
524 // Add to ClientEvent queue
526 event.type = CE_PLAYER_DAMAGE;
527 event.player_damage.amount = oldhp - hp;
528 m_client_event_queue.push(event);
532 void Client::handleCommand_Breath(NetworkPacket* pkt)
534 Player *player = m_env.getLocalPlayer();
535 assert(player != NULL);
541 player->setBreath(breath);
544 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
546 Player *player = m_env.getLocalPlayer();
547 assert(player != NULL);
552 *pkt >> pos >> pitch >> yaw;
554 player->setPosition(pos);
556 infostream << "Client got TOCLIENT_MOVE_PLAYER"
557 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
558 << " pitch=" << pitch
563 Add to ClientEvent queue.
564 This has to be sent to the main program because otherwise
565 it would just force the pitch and yaw values to whatever
566 the camera points to.
569 event.type = CE_PLAYER_FORCE_MOVE;
570 event.player_force_move.pitch = pitch;
571 event.player_force_move.yaw = yaw;
572 m_client_event_queue.push(event);
574 // Ignore damage for a few seconds, so that the player doesn't
575 // get damage from falling on ground
576 m_ignore_damage_timer = 3.0;
579 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
581 infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
584 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
586 bool set_camera_point_target;
587 v3f camera_point_target;
589 *pkt >> set_camera_point_target;
590 *pkt >> camera_point_target;
593 event.type = CE_DEATHSCREEN;
594 event.deathscreen.set_camera_point_target = set_camera_point_target;
595 event.deathscreen.camera_point_target_x = camera_point_target.X;
596 event.deathscreen.camera_point_target_y = camera_point_target.Y;
597 event.deathscreen.camera_point_target_z = camera_point_target.Z;
598 m_client_event_queue.push(event);
601 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
607 infostream << "Client: Received media announcement: packet size: "
608 << pkt->getSize() << std::endl;
610 if (m_media_downloader == NULL ||
611 m_media_downloader->isStarted()) {
612 const char *problem = m_media_downloader ?
613 "we already saw another announcement" :
614 "all media has been received already";
615 errorstream << "Client: Received media announcement but "
617 << " files=" << num_files
618 << " size=" << pkt->getSize() << std::endl;
622 // Mesh update thread must be stopped while
623 // updating content definitions
624 sanity_check(!m_mesh_update_thread.isRunning());
626 for (u16 i = 0; i < num_files; i++) {
627 std::string name, sha1_base64;
629 *pkt >> name >> sha1_base64;
631 std::string sha1_raw = base64_decode(sha1_base64);
632 m_media_downloader->addFile(name, sha1_raw);
635 std::vector<std::string> remote_media;
643 std::string baseurl = trim(sf.next(","));
645 m_media_downloader->addRemoteServer(baseurl);
648 catch(SerializationError& e) {
649 // not supported by server or turned off
652 m_media_downloader->step(this);
655 void Client::handleCommand_Media(NetworkPacket* pkt)
659 u16 total number of file bunches
660 u16 index of this bunch
661 u32 number of files in this bunch
673 *pkt >> num_bunches >> bunch_i >> num_files;
675 infostream << "Client: Received files: bunch " << bunch_i << "/"
676 << num_bunches << " files=" << num_files
677 << " size=" << pkt->getSize() << std::endl;
682 if (m_media_downloader == NULL ||
683 !m_media_downloader->isStarted()) {
684 const char *problem = m_media_downloader ?
685 "media has not been requested" :
686 "all media has been received already";
687 errorstream << "Client: Received media but "
689 << " bunch " << bunch_i << "/" << num_bunches
690 << " files=" << num_files
691 << " size=" << pkt->getSize() << std::endl;
695 // Mesh update thread must be stopped while
696 // updating content definitions
697 sanity_check(!m_mesh_update_thread.isRunning());
699 for (u32 i=0; i < num_files; i++) {
704 std::string data = pkt->readLongString();
706 m_media_downloader->conventionalTransferDone(
711 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
713 infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl;
716 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
718 infostream << "Client: Received node definitions: packet size: "
719 << pkt->getSize() << std::endl;
721 // Mesh update thread must be stopped while
722 // updating content definitions
723 sanity_check(!m_mesh_update_thread.isRunning());
725 // Decompress node definitions
726 std::string datastring(pkt->getString(0), pkt->getSize());
727 std::istringstream is(datastring, std::ios_base::binary);
728 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
729 std::ostringstream tmp_os;
730 decompressZlib(tmp_is, tmp_os);
732 // Deserialize node definitions
733 std::istringstream tmp_is2(tmp_os.str());
734 m_nodedef->deSerialize(tmp_is2);
735 m_nodedef_received = true;
738 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
740 infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
743 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
745 infostream << "Client: Received item definitions: packet size: "
746 << pkt->getSize() << std::endl;
748 // Mesh update thread must be stopped while
749 // updating content definitions
750 sanity_check(!m_mesh_update_thread.isRunning());
752 // Decompress item definitions
753 std::string datastring(pkt->getString(0), pkt->getSize());
754 std::istringstream is(datastring, std::ios_base::binary);
755 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
756 std::ostringstream tmp_os;
757 decompressZlib(tmp_is, tmp_os);
759 // Deserialize node definitions
760 std::istringstream tmp_is2(tmp_os.str());
761 m_itemdef->deSerialize(tmp_is2);
762 m_itemdef_received = true;
765 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
770 u8 type; // 0=local, 1=positional, 2=object
775 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
781 client_id = m_sound->playSound(name, loop, gain);
783 case 1: // positional
784 client_id = m_sound->playSoundAt(name, loop, gain, pos);
788 ClientActiveObject *cao = m_env.getActiveObject(object_id);
790 pos = cao->getPosition();
791 client_id = m_sound->playSoundAt(name, loop, gain, pos);
792 // TODO: Set up sound to move with object
799 if (client_id != -1) {
800 m_sounds_server_to_client[server_id] = client_id;
801 m_sounds_client_to_server[client_id] = server_id;
803 m_sounds_to_objects[client_id] = object_id;
807 void Client::handleCommand_StopSound(NetworkPacket* pkt)
813 std::map<s32, int>::iterator i =
814 m_sounds_server_to_client.find(server_id);
816 if (i != m_sounds_server_to_client.end()) {
817 int client_id = i->second;
818 m_sound->stopSound(client_id);
822 void Client::handleCommand_Privileges(NetworkPacket* pkt)
824 m_privileges.clear();
825 infostream << "Client: Privileges updated: ";
828 *pkt >> num_privileges;
830 for (u16 i = 0; i < num_privileges; i++) {
835 m_privileges.insert(priv);
836 infostream << priv << " ";
838 infostream << std::endl;
841 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
843 Player *player = m_env.getLocalPlayer();
844 assert(player != NULL);
846 // Store formspec in LocalPlayer
847 player->inventory_formspec = pkt->readLongString();
850 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
852 std::string datastring(pkt->getString(0), pkt->getSize());
853 std::istringstream is(datastring, std::ios_base::binary);
855 std::string name = deSerializeString(is);
857 infostream << "Client: Detached inventory update: \"" << name
858 << "\"" << std::endl;
860 Inventory *inv = NULL;
861 if (m_detached_inventories.count(name) > 0)
862 inv = m_detached_inventories[name];
864 inv = new Inventory(m_itemdef);
865 m_detached_inventories[name] = inv;
867 inv->deSerialize(is);
870 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
872 std::string formspec = pkt->readLongString();
873 std::string formname;
878 event.type = CE_SHOW_FORMSPEC;
879 // pointer is required as event is a struct only!
880 // adding a std:string to a struct isn't possible
881 event.show_formspec.formspec = new std::string(formspec);
882 event.show_formspec.formname = new std::string(formname);
883 m_client_event_queue.push(event);
886 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
888 std::string datastring(pkt->getString(0), pkt->getSize());
889 std::istringstream is(datastring, std::ios_base::binary);
891 v3f pos = readV3F1000(is);
892 v3f vel = readV3F1000(is);
893 v3f acc = readV3F1000(is);
894 float expirationtime = readF1000(is);
895 float size = readF1000(is);
896 bool collisiondetection = readU8(is);
897 std::string texture = deSerializeLongString(is);
898 bool vertical = false;
900 vertical = readU8(is);
904 event.type = CE_SPAWN_PARTICLE;
905 event.spawn_particle.pos = new v3f (pos);
906 event.spawn_particle.vel = new v3f (vel);
907 event.spawn_particle.acc = new v3f (acc);
908 event.spawn_particle.expirationtime = expirationtime;
909 event.spawn_particle.size = size;
910 event.spawn_particle.collisiondetection = collisiondetection;
911 event.spawn_particle.vertical = vertical;
912 event.spawn_particle.texture = new std::string(texture);
914 m_client_event_queue.push(event);
917 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
931 bool collisiondetection;
934 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
935 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
936 >> maxsize >> collisiondetection;
938 std::string texture = pkt->readLongString();
942 bool vertical = false;
948 event.type = CE_ADD_PARTICLESPAWNER;
949 event.add_particlespawner.amount = amount;
950 event.add_particlespawner.spawntime = spawntime;
951 event.add_particlespawner.minpos = new v3f (minpos);
952 event.add_particlespawner.maxpos = new v3f (maxpos);
953 event.add_particlespawner.minvel = new v3f (minvel);
954 event.add_particlespawner.maxvel = new v3f (maxvel);
955 event.add_particlespawner.minacc = new v3f (minacc);
956 event.add_particlespawner.maxacc = new v3f (maxacc);
957 event.add_particlespawner.minexptime = minexptime;
958 event.add_particlespawner.maxexptime = maxexptime;
959 event.add_particlespawner.minsize = minsize;
960 event.add_particlespawner.maxsize = maxsize;
961 event.add_particlespawner.collisiondetection = collisiondetection;
962 event.add_particlespawner.vertical = vertical;
963 event.add_particlespawner.texture = new std::string(texture);
964 event.add_particlespawner.id = id;
966 m_client_event_queue.push(event);
970 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
975 // Modification set 13/03/15, 1 year of compat for protocol v24
976 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
985 event.type = CE_DELETE_PARTICLESPAWNER;
986 event.delete_particlespawner.id =
987 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
989 m_client_event_queue.push(event);
992 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
994 std::string datastring(pkt->getString(0), pkt->getSize());
995 std::istringstream is(datastring, std::ios_base::binary);
1011 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
1012 >> dir >> align >> offset;
1016 catch(SerializationError &e) {};
1020 } catch(SerializationError &e) {};
1023 event.type = CE_HUDADD;
1024 event.hudadd.id = id;
1025 event.hudadd.type = type;
1026 event.hudadd.pos = new v2f(pos);
1027 event.hudadd.name = new std::string(name);
1028 event.hudadd.scale = new v2f(scale);
1029 event.hudadd.text = new std::string(text);
1030 event.hudadd.number = number;
1031 event.hudadd.item = item;
1032 event.hudadd.dir = dir;
1033 event.hudadd.align = new v2f(align);
1034 event.hudadd.offset = new v2f(offset);
1035 event.hudadd.world_pos = new v3f(world_pos);
1036 event.hudadd.size = new v2s32(size);
1037 m_client_event_queue.push(event);
1040 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1047 event.type = CE_HUDRM;
1048 event.hudrm.id = id;
1049 m_client_event_queue.push(event);
1052 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1064 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1065 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1067 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1069 else if (stat == HUD_STAT_WORLD_POS)
1071 else if (stat == HUD_STAT_SIZE )
1077 event.type = CE_HUDCHANGE;
1078 event.hudchange.id = id;
1079 event.hudchange.stat = (HudElementStat)stat;
1080 event.hudchange.v2fdata = new v2f(v2fdata);
1081 event.hudchange.v3fdata = new v3f(v3fdata);
1082 event.hudchange.sdata = new std::string(sdata);
1083 event.hudchange.data = intdata;
1084 event.hudchange.v2s32data = new v2s32(v2s32data);
1085 m_client_event_queue.push(event);
1088 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1092 *pkt >> flags >> mask;
1094 Player *player = m_env.getLocalPlayer();
1095 assert(player != NULL);
1097 player->hud_flags &= ~mask;
1098 player->hud_flags |= flags;
1101 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1103 u16 param; std::string value;
1105 *pkt >> param >> value;
1107 Player *player = m_env.getLocalPlayer();
1108 assert(player != NULL);
1110 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1111 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1112 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1113 player->hud_hotbar_itemcount = hotbar_itemcount;
1115 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1116 ((LocalPlayer *) player)->hotbar_image = value;
1118 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1119 ((LocalPlayer *) player)->hotbar_selected_image = value;
1123 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1125 std::string datastring(pkt->getString(0), pkt->getSize());
1126 std::istringstream is(datastring, std::ios_base::binary);
1128 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1129 std::string *type = new std::string(deSerializeString(is));
1130 u16 count = readU16(is);
1131 std::vector<std::string> *params = new std::vector<std::string>;
1133 for (size_t i = 0; i < count; i++)
1134 params->push_back(deSerializeString(is));
1137 event.type = CE_SET_SKY;
1138 event.set_sky.bgcolor = bgcolor;
1139 event.set_sky.type = type;
1140 event.set_sky.params = params;
1141 m_client_event_queue.push(event);
1144 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1147 u16 day_night_ratio_u;
1149 *pkt >> do_override >> day_night_ratio_u;
1151 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1154 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1155 event.override_day_night_ratio.do_override = do_override;
1156 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1157 m_client_event_queue.push(event);
1160 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1162 LocalPlayer *player = m_env.getLocalPlayer();
1163 assert(player != NULL);
1165 *pkt >> player->local_animations[0];
1166 *pkt >> player->local_animations[1];
1167 *pkt >> player->local_animations[2];
1168 *pkt >> player->local_animations[3];
1169 *pkt >> player->local_animation_speed;
1172 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1174 LocalPlayer *player = m_env.getLocalPlayer();
1175 assert(player != NULL);
1177 *pkt >> player->eye_offset_first >> player->eye_offset_third;
1180 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1182 if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
1183 && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
1184 errorstream << "Client: Recieved SRP S_B login message,"
1185 << " but wasn't supposed to (chosen_mech="
1186 << m_chosen_auth_mech << ")." << std::endl;
1192 SRPUser *usr = (SRPUser *) m_auth_data;
1197 infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;
1199 srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1200 (const unsigned char *) B.c_str(), B.size(),
1201 (unsigned char **) &bytes_M, &len_M);
1204 errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1208 NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1209 resp_pkt << std::string(bytes_M, len_M);