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"
34 void Client::handleCommand_Deprecated(NetworkPacket* pkt)
36 infostream << "Got deprecated command "
37 << toClientCommandTable[pkt->getCommand()].name << " from peer "
38 << pkt->getPeerId() << "!" << std::endl;
41 void Client::handleCommand_Hello(NetworkPacket* pkt)
43 if (pkt->getSize() < 1)
49 infostream << "Client: TOCLIENT_HELLO received with "
50 "deployed=" << ((int)deployed & 0xff) << std::endl;
52 if (!ser_ver_supported(deployed)) {
53 infostream << "Client: TOCLIENT_HELLO: Server sent "
54 << "unsupported ser_fmt_ver"<< std::endl;
58 m_server_ser_ver = deployed;
60 // @ TODO auth to server
63 void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
66 *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval;
68 playerpos -= v3f(0, BS / 2, 0);
70 // Set player position
71 Player *player = m_env.getLocalPlayer();
72 assert(player != NULL);
73 player->setPosition(playerpos);
75 infostream << "Client: received map seed: " << m_map_seed << std::endl;
76 infostream << "Client: received recommended send interval "
77 << m_recommended_send_interval<<std::endl;
80 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
86 void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
88 if (pkt->getSize() < 1)
94 infostream << "Client: TOCLIENT_INIT_LEGACY received with "
95 "deployed=" << ((int)deployed & 0xff) << std::endl;
97 if (!ser_ver_supported(deployed)) {
98 infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent "
99 << "unsupported ser_fmt_ver"<< std::endl;
103 m_server_ser_ver = deployed;
105 // Get player position
106 v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0);
107 if (pkt->getSize() >= 1 + 6) {
108 *pkt >> playerpos_s16;
110 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0);
113 // Set player position
114 Player *player = m_env.getLocalPlayer();
115 assert(player != NULL);
116 player->setPosition(playerpos_f);
118 if (pkt->getSize() >= 1 + 6 + 8) {
121 infostream << "Client: received map seed: " << m_map_seed << std::endl;
124 if (pkt->getSize() >= 1 + 6 + 8 + 4) {
125 *pkt >> m_recommended_send_interval;
126 infostream << "Client: received recommended send interval "
127 << m_recommended_send_interval<<std::endl;
131 NetworkPacket resp_pkt(TOSERVER_INIT2, 0);
137 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
139 // The server didn't like our password. Note, this needs
140 // to be processed even if the serialisation format has
141 // not been agreed yet, the same as TOCLIENT_INIT.
142 m_access_denied = true;
143 m_access_denied_reason = L"Unknown";
145 if (pkt->getCommand() == TOCLIENT_ACCESS_DENIED) {
146 if (pkt->getSize() < 1)
149 u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
151 if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
152 *pkt >> m_access_denied_reason;
154 else if (denyCode < SERVER_ACCESSDENIED_MAX) {
155 m_access_denied_reason = accessDeniedStrings[denyCode];
158 // 13/03/15 Legacy code from 0.4.12 and lesser. must stay 1 year
159 // for compat with old clients
161 if (pkt->getSize() >= 2) {
162 *pkt >> m_access_denied_reason;
167 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
169 if (pkt->getSize() < 6)
177 void Client::handleCommand_AddNode(NetworkPacket* pkt)
179 if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
186 n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
188 bool remove_metadata = true;
189 u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
190 if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
191 remove_metadata = false;
194 addNode(p, n, remove_metadata);
196 void Client::handleCommand_BlockData(NetworkPacket* pkt)
198 // Ignore too small packet
199 if (pkt->getSize() < 6)
205 std::string datastring(pkt->getString(6), pkt->getSize() - 6);
206 std::istringstream istr(datastring, std::ios_base::binary);
212 sector = m_env.getMap().emergeSector(p2d);
214 assert(sector->getPos() == p2d);
216 block = sector->getBlockNoCreateNoEx(p.Y);
219 Update an existing block
221 block->deSerialize(istr, m_server_ser_ver, false);
222 block->deSerializeNetworkSpecific(istr);
228 block = new MapBlock(&m_env.getMap(), p, this);
229 block->deSerialize(istr, m_server_ser_ver, false);
230 block->deSerializeNetworkSpecific(istr);
231 sector->insertBlock(block);
235 ServerMap::saveBlock(block, m_localdb);
239 Add it to mesh update queue and set it to be acknowledged after update.
241 addUpdateMeshTaskWithEdge(p, true);
244 void Client::handleCommand_Inventory(NetworkPacket* pkt)
246 if (pkt->getSize() < 1)
249 std::string datastring(pkt->getString(0), pkt->getSize());
250 std::istringstream is(datastring, std::ios_base::binary);
252 Player *player = m_env.getLocalPlayer();
253 assert(player != NULL);
255 player->inventory.deSerialize(is);
257 m_inventory_updated = true;
259 delete m_inventory_from_server;
260 m_inventory_from_server = new Inventory(player->inventory);
261 m_inventory_from_server_age = 0.0;
264 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
266 if (pkt->getSize() < 2)
273 time_of_day = time_of_day % 24000;
274 float time_speed = 0;
276 if (pkt->getSize() >= 2 + 4) {
280 // Old message; try to approximate speed of time by ourselves
281 float time_of_day_f = (float)time_of_day / 24000.0;
282 float tod_diff_f = 0;
284 if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
285 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
287 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
289 m_last_time_of_day_f = time_of_day_f;
290 float time_diff = m_time_of_day_update_timer;
291 m_time_of_day_update_timer = 0;
293 if (m_time_of_day_set) {
294 time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff;
295 infostream << "Client: Measured time_of_day speed (old format): "
296 << time_speed << " tod_diff_f=" << tod_diff_f
297 << " time_diff=" << time_diff << std::endl;
301 // Update environment
302 m_env.setTimeOfDay(time_of_day);
303 m_env.setTimeOfDaySpeed(time_speed);
304 m_time_of_day_set = true;
306 u32 dr = m_env.getDayNightRatio();
307 infostream << "Client: time_of_day=" << time_of_day
308 << " time_speed=" << time_speed
309 << " dr=" << dr << std::endl;
312 void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
323 std::wstring message;
324 for (u32 i = 0; i < len; i++) {
326 message += (wchar_t)read_wchar;
329 m_chat_queue.push(message);
332 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
336 u16 count of removed objects
337 for all removed objects {
340 u16 count of added objects
341 for all added objects {
344 u32 initialization data length
345 string initialization data
349 // Read removed objects
351 u16 removed_count, added_count, id;
353 *pkt >> removed_count;
355 for (u16 i = 0; i < removed_count; i++) {
357 m_env.removeActiveObject(id);
360 // Read added objects
363 for (u16 i = 0; i < added_count; i++) {
365 m_env.addActiveObject(id, type, pkt->readLongString());
369 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
381 // Get all data except the command number
382 std::string datastring(pkt->getString(0), pkt->getSize());
383 // Throw them in an istringstream
384 std::istringstream is(datastring, std::ios_base::binary);
386 while(is.eof() == false) {
388 u16 id = readU16((u8*)buf);
392 size_t message_size = readU16((u8*)buf);
394 message.reserve(message_size);
395 for (u32 i = 0; i < message_size; i++) {
397 message.append(buf, 1);
399 // Pass on to the environment
400 m_env.processActiveObjectMessage(id, message);
404 void Client::handleCommand_Movement(NetworkPacket* pkt)
406 Player *player = m_env.getLocalPlayer();
407 assert(player != NULL);
409 float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
411 *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
412 >> lf >> lfs >> ls >> g;
414 player->movement_acceleration_default = mad * BS;
415 player->movement_acceleration_air = maa * BS;
416 player->movement_acceleration_fast = maf * BS;
417 player->movement_speed_walk = msw * BS;
418 player->movement_speed_crouch = mscr * BS;
419 player->movement_speed_fast = msf * BS;
420 player->movement_speed_climb = mscl * BS;
421 player->movement_speed_jump = msj * BS;
422 player->movement_liquid_fluidity = lf * BS;
423 player->movement_liquid_fluidity_smooth = lfs * BS;
424 player->movement_liquid_sink = ls * BS;
425 player->movement_gravity = g * BS;
428 void Client::handleCommand_HP(NetworkPacket* pkt)
431 Player *player = m_env.getLocalPlayer();
432 assert(player != NULL);
434 u8 oldhp = player->hp;
442 // Add to ClientEvent queue
444 event.type = CE_PLAYER_DAMAGE;
445 event.player_damage.amount = oldhp - hp;
446 m_client_event_queue.push(event);
450 void Client::handleCommand_Breath(NetworkPacket* pkt)
452 Player *player = m_env.getLocalPlayer();
453 assert(player != NULL);
459 player->setBreath(breath);
462 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
464 Player *player = m_env.getLocalPlayer();
465 assert(player != NULL);
470 *pkt >> pos >> pitch >> yaw;
472 player->setPosition(pos);
474 infostream << "Client got TOCLIENT_MOVE_PLAYER"
475 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
476 << " pitch=" << pitch
481 Add to ClientEvent queue.
482 This has to be sent to the main program because otherwise
483 it would just force the pitch and yaw values to whatever
484 the camera points to.
487 event.type = CE_PLAYER_FORCE_MOVE;
488 event.player_force_move.pitch = pitch;
489 event.player_force_move.yaw = yaw;
490 m_client_event_queue.push(event);
492 // Ignore damage for a few seconds, so that the player doesn't
493 // get damage from falling on ground
494 m_ignore_damage_timer = 3.0;
497 void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
499 infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
502 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
504 bool set_camera_point_target;
505 v3f camera_point_target;
507 *pkt >> set_camera_point_target;
508 *pkt >> camera_point_target;
511 event.type = CE_DEATHSCREEN;
512 event.deathscreen.set_camera_point_target = set_camera_point_target;
513 event.deathscreen.camera_point_target_x = camera_point_target.X;
514 event.deathscreen.camera_point_target_y = camera_point_target.Y;
515 event.deathscreen.camera_point_target_z = camera_point_target.Z;
516 m_client_event_queue.push(event);
519 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
525 infostream << "Client: Received media announcement: packet size: "
526 << pkt->getSize() << std::endl;
528 if (m_media_downloader == NULL ||
529 m_media_downloader->isStarted()) {
530 const char *problem = m_media_downloader ?
531 "we already saw another announcement" :
532 "all media has been received already";
533 errorstream << "Client: Received media announcement but "
535 << " files=" << num_files
536 << " size=" << pkt->getSize() << std::endl;
540 // Mesh update thread must be stopped while
541 // updating content definitions
542 sanity_check(!m_mesh_update_thread.IsRunning());
544 for (u16 i = 0; i < num_files; i++) {
545 std::string name, sha1_base64;
547 *pkt >> name >> sha1_base64;
549 std::string sha1_raw = base64_decode(sha1_base64);
550 m_media_downloader->addFile(name, sha1_raw);
553 std::vector<std::string> remote_media;
561 std::string baseurl = trim(sf.next(","));
563 m_media_downloader->addRemoteServer(baseurl);
566 catch(SerializationError& e) {
567 // not supported by server or turned off
570 m_media_downloader->step(this);
573 void Client::handleCommand_Media(NetworkPacket* pkt)
577 u16 total number of file bunches
578 u16 index of this bunch
579 u32 number of files in this bunch
591 *pkt >> num_bunches >> bunch_i >> num_files;
593 infostream << "Client: Received files: bunch " << bunch_i << "/"
594 << num_bunches << " files=" << num_files
595 << " size=" << pkt->getSize() << std::endl;
600 if (m_media_downloader == NULL ||
601 !m_media_downloader->isStarted()) {
602 const char *problem = m_media_downloader ?
603 "media has not been requested" :
604 "all media has been received already";
605 errorstream << "Client: Received media but "
607 << " bunch " << bunch_i << "/" << num_bunches
608 << " files=" << num_files
609 << " size=" << pkt->getSize() << std::endl;
613 // Mesh update thread must be stopped while
614 // updating content definitions
615 sanity_check(!m_mesh_update_thread.IsRunning());
617 for (u32 i=0; i < num_files; i++) {
622 std::string data = pkt->readLongString();
624 m_media_downloader->conventionalTransferDone(
629 void Client::handleCommand_ToolDef(NetworkPacket* pkt)
631 infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl;
634 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
636 infostream << "Client: Received node definitions: packet size: "
637 << pkt->getSize() << std::endl;
639 // Mesh update thread must be stopped while
640 // updating content definitions
641 sanity_check(!m_mesh_update_thread.IsRunning());
643 // Decompress node definitions
644 std::string datastring(pkt->getString(0), pkt->getSize());
645 std::istringstream is(datastring, std::ios_base::binary);
646 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
647 std::ostringstream tmp_os;
648 decompressZlib(tmp_is, tmp_os);
650 // Deserialize node definitions
651 std::istringstream tmp_is2(tmp_os.str());
652 m_nodedef->deSerialize(tmp_is2);
653 m_nodedef_received = true;
656 void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
658 infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
661 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
663 infostream << "Client: Received item definitions: packet size: "
664 << pkt->getSize() << std::endl;
666 // Mesh update thread must be stopped while
667 // updating content definitions
668 sanity_check(!m_mesh_update_thread.IsRunning());
670 // Decompress item definitions
671 std::string datastring(pkt->getString(0), pkt->getSize());
672 std::istringstream is(datastring, std::ios_base::binary);
673 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
674 std::ostringstream tmp_os;
675 decompressZlib(tmp_is, tmp_os);
677 // Deserialize node definitions
678 std::istringstream tmp_is2(tmp_os.str());
679 m_itemdef->deSerialize(tmp_is2);
680 m_itemdef_received = true;
683 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
688 u8 type; // 0=local, 1=positional, 2=object
693 *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
699 client_id = m_sound->playSound(name, loop, gain);
701 case 1: // positional
702 client_id = m_sound->playSoundAt(name, loop, gain, pos);
706 ClientActiveObject *cao = m_env.getActiveObject(object_id);
708 pos = cao->getPosition();
709 client_id = m_sound->playSoundAt(name, loop, gain, pos);
710 // TODO: Set up sound to move with object
717 if (client_id != -1) {
718 m_sounds_server_to_client[server_id] = client_id;
719 m_sounds_client_to_server[client_id] = server_id;
721 m_sounds_to_objects[client_id] = object_id;
725 void Client::handleCommand_StopSound(NetworkPacket* pkt)
731 std::map<s32, int>::iterator i =
732 m_sounds_server_to_client.find(server_id);
734 if (i != m_sounds_server_to_client.end()) {
735 int client_id = i->second;
736 m_sound->stopSound(client_id);
740 void Client::handleCommand_Privileges(NetworkPacket* pkt)
742 m_privileges.clear();
743 infostream << "Client: Privileges updated: ";
746 *pkt >> num_privileges;
748 for (u16 i = 0; i < num_privileges; i++) {
753 m_privileges.insert(priv);
754 infostream << priv << " ";
756 infostream << std::endl;
759 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
761 Player *player = m_env.getLocalPlayer();
762 assert(player != NULL);
764 // Store formspec in LocalPlayer
765 player->inventory_formspec = pkt->readLongString();
768 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
770 std::string datastring(pkt->getString(0), pkt->getSize());
771 std::istringstream is(datastring, std::ios_base::binary);
773 std::string name = deSerializeString(is);
775 infostream << "Client: Detached inventory update: \"" << name
776 << "\"" << std::endl;
778 Inventory *inv = NULL;
779 if (m_detached_inventories.count(name) > 0)
780 inv = m_detached_inventories[name];
782 inv = new Inventory(m_itemdef);
783 m_detached_inventories[name] = inv;
785 inv->deSerialize(is);
788 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
790 std::string formspec = pkt->readLongString();
791 std::string formname;
796 event.type = CE_SHOW_FORMSPEC;
797 // pointer is required as event is a struct only!
798 // adding a std:string to a struct isn't possible
799 event.show_formspec.formspec = new std::string(formspec);
800 event.show_formspec.formname = new std::string(formname);
801 m_client_event_queue.push(event);
804 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
806 std::string datastring(pkt->getString(0), pkt->getSize());
807 std::istringstream is(datastring, std::ios_base::binary);
809 v3f pos = readV3F1000(is);
810 v3f vel = readV3F1000(is);
811 v3f acc = readV3F1000(is);
812 float expirationtime = readF1000(is);
813 float size = readF1000(is);
814 bool collisiondetection = readU8(is);
815 std::string texture = deSerializeLongString(is);
816 bool vertical = false;
818 vertical = readU8(is);
822 event.type = CE_SPAWN_PARTICLE;
823 event.spawn_particle.pos = new v3f (pos);
824 event.spawn_particle.vel = new v3f (vel);
825 event.spawn_particle.acc = new v3f (acc);
826 event.spawn_particle.expirationtime = expirationtime;
827 event.spawn_particle.size = size;
828 event.spawn_particle.collisiondetection = collisiondetection;
829 event.spawn_particle.vertical = vertical;
830 event.spawn_particle.texture = new std::string(texture);
832 m_client_event_queue.push(event);
835 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
849 bool collisiondetection;
852 *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
853 >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
854 >> maxsize >> collisiondetection;
856 std::string texture = pkt->readLongString();
860 bool vertical = false;
866 event.type = CE_ADD_PARTICLESPAWNER;
867 event.add_particlespawner.amount = amount;
868 event.add_particlespawner.spawntime = spawntime;
869 event.add_particlespawner.minpos = new v3f (minpos);
870 event.add_particlespawner.maxpos = new v3f (maxpos);
871 event.add_particlespawner.minvel = new v3f (minvel);
872 event.add_particlespawner.maxvel = new v3f (maxvel);
873 event.add_particlespawner.minacc = new v3f (minacc);
874 event.add_particlespawner.maxacc = new v3f (maxacc);
875 event.add_particlespawner.minexptime = minexptime;
876 event.add_particlespawner.maxexptime = maxexptime;
877 event.add_particlespawner.minsize = minsize;
878 event.add_particlespawner.maxsize = maxsize;
879 event.add_particlespawner.collisiondetection = collisiondetection;
880 event.add_particlespawner.vertical = vertical;
881 event.add_particlespawner.texture = new std::string(texture);
882 event.add_particlespawner.id = id;
884 m_client_event_queue.push(event);
888 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
893 // Modification set 13/03/15, 1 year of compat for protocol v24
894 if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) {
903 event.type = CE_DELETE_PARTICLESPAWNER;
904 event.delete_particlespawner.id =
905 (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id);
907 m_client_event_queue.push(event);
910 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
912 std::string datastring(pkt->getString(0), pkt->getSize());
913 std::istringstream is(datastring, std::ios_base::binary);
929 *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
930 >> dir >> align >> offset;
934 catch(SerializationError &e) {};
938 } catch(SerializationError &e) {};
941 event.type = CE_HUDADD;
942 event.hudadd.id = id;
943 event.hudadd.type = type;
944 event.hudadd.pos = new v2f(pos);
945 event.hudadd.name = new std::string(name);
946 event.hudadd.scale = new v2f(scale);
947 event.hudadd.text = new std::string(text);
948 event.hudadd.number = number;
949 event.hudadd.item = item;
950 event.hudadd.dir = dir;
951 event.hudadd.align = new v2f(align);
952 event.hudadd.offset = new v2f(offset);
953 event.hudadd.world_pos = new v3f(world_pos);
954 event.hudadd.size = new v2s32(size);
955 m_client_event_queue.push(event);
958 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
965 event.type = CE_HUDRM;
967 m_client_event_queue.push(event);
970 void Client::handleCommand_HudChange(NetworkPacket* pkt)
982 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
983 stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
985 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
987 else if (stat == HUD_STAT_WORLD_POS)
989 else if (stat == HUD_STAT_SIZE )
995 event.type = CE_HUDCHANGE;
996 event.hudchange.id = id;
997 event.hudchange.stat = (HudElementStat)stat;
998 event.hudchange.v2fdata = new v2f(v2fdata);
999 event.hudchange.v3fdata = new v3f(v3fdata);
1000 event.hudchange.sdata = new std::string(sdata);
1001 event.hudchange.data = intdata;
1002 event.hudchange.v2s32data = new v2s32(v2s32data);
1003 m_client_event_queue.push(event);
1006 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1010 *pkt >> flags >> mask;
1012 Player *player = m_env.getLocalPlayer();
1013 assert(player != NULL);
1015 player->hud_flags &= ~mask;
1016 player->hud_flags |= flags;
1019 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1021 u16 param; std::string value;
1023 *pkt >> param >> value;
1025 Player *player = m_env.getLocalPlayer();
1026 assert(player != NULL);
1028 if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1029 s32 hotbar_itemcount = readS32((u8*) value.c_str());
1030 if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1031 player->hud_hotbar_itemcount = hotbar_itemcount;
1033 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1034 ((LocalPlayer *) player)->hotbar_image = value;
1036 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1037 ((LocalPlayer *) player)->hotbar_selected_image = value;
1041 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1043 std::string datastring(pkt->getString(0), pkt->getSize());
1044 std::istringstream is(datastring, std::ios_base::binary);
1046 video::SColor *bgcolor = new video::SColor(readARGB8(is));
1047 std::string *type = new std::string(deSerializeString(is));
1048 u16 count = readU16(is);
1049 std::vector<std::string> *params = new std::vector<std::string>;
1051 for (size_t i = 0; i < count; i++)
1052 params->push_back(deSerializeString(is));
1055 event.type = CE_SET_SKY;
1056 event.set_sky.bgcolor = bgcolor;
1057 event.set_sky.type = type;
1058 event.set_sky.params = params;
1059 m_client_event_queue.push(event);
1062 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1065 u16 day_night_ratio_u;
1067 *pkt >> do_override >> day_night_ratio_u;
1069 float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1072 event.type = CE_OVERRIDE_DAY_NIGHT_RATIO;
1073 event.override_day_night_ratio.do_override = do_override;
1074 event.override_day_night_ratio.ratio_f = day_night_ratio_f;
1075 m_client_event_queue.push(event);
1078 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1080 LocalPlayer *player = m_env.getLocalPlayer();
1081 assert(player != NULL);
1083 *pkt >> player->local_animations[0];
1084 *pkt >> player->local_animations[1];
1085 *pkt >> player->local_animations[2];
1086 *pkt >> player->local_animations[3];
1087 *pkt >> player->local_animation_speed;
1090 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1092 LocalPlayer *player = m_env.getLocalPlayer();
1093 assert(player != NULL);
1095 *pkt >> player->eye_offset_first >> player->eye_offset_third;