1 /*
2 Minetest
3 Copyright (C) 2015 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
4 
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.
9 
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.
14 
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.
18 */
19 
20 #include "client/client.h"
21 
22 #include "util/base64.h"
23 #include "client/camera.h"
24 #include "chatmessage.h"
25 #include "client/clientmedia.h"
26 #include "log.h"
27 #include "map.h"
28 #include "mapsector.h"
29 #include "client/minimap.h"
30 #include "modchannels.h"
31 #include "nodedef.h"
32 #include "serialization.h"
33 #include "server.h"
34 #include "util/strfnd.h"
35 #include "client/clientevent.h"
36 #include "client/sound.h"
37 #include "network/clientopcodes.h"
38 #include "network/connection.h"
39 #include "script/scripting_client.h"
40 #include "util/serialize.h"
41 #include "util/srp.h"
42 #include "util/sha1.h"
43 #include "tileanimation.h"
44 #include "gettext.h"
45 #include "skyparams.h"
46 
handleCommand_Deprecated(NetworkPacket * pkt)47 void Client::handleCommand_Deprecated(NetworkPacket* pkt)
48 {
49 	infostream << "Got deprecated command "
50 			<< toClientCommandTable[pkt->getCommand()].name << " from peer "
51 			<< pkt->getPeerId() << "!" << std::endl;
52 }
53 
handleCommand_Hello(NetworkPacket * pkt)54 void Client::handleCommand_Hello(NetworkPacket* pkt)
55 {
56 	if (pkt->getSize() < 1)
57 		return;
58 
59 	u8 serialization_ver;
60 	u16 proto_ver;
61 	u16 compression_mode;
62 	u32 auth_mechs;
63 	std::string username_legacy; // for case insensitivity
64 	*pkt >> serialization_ver >> compression_mode >> proto_ver
65 		>> auth_mechs >> username_legacy;
66 
67 	// Chose an auth method we support
68 	AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);
69 
70 	infostream << "Client: TOCLIENT_HELLO received with "
71 			<< "serialization_ver=" << (u32)serialization_ver
72 			<< ", auth_mechs=" << auth_mechs
73 			<< ", proto_ver=" << proto_ver
74 			<< ", compression_mode=" << compression_mode
75 			<< ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
76 
77 	if (!ser_ver_supported(serialization_ver)) {
78 		infostream << "Client: TOCLIENT_HELLO: Server sent "
79 				<< "unsupported ser_fmt_ver"<< std::endl;
80 		return;
81 	}
82 
83 	m_server_ser_ver = serialization_ver;
84 	m_proto_ver = proto_ver;
85 
86 	//TODO verify that username_legacy matches sent username, only
87 	// differs in casing (make both uppercase and compare)
88 	// This is only neccessary though when we actually want to add casing support
89 
90 	if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
91 		// we recieved a TOCLIENT_HELLO while auth was already going on
92 		errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
93 			<< "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
94 		if (m_chosen_auth_mech == AUTH_MECHANISM_SRP ||
95 				m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD) {
96 			srp_user_delete((SRPUser *) m_auth_data);
97 			m_auth_data = 0;
98 		}
99 	}
100 
101 	// Authenticate using that method, or abort if there wasn't any method found
102 	if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
103 		if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP &&
104 				!m_simple_singleplayer_mode &&
105 				!getServerAddress().isLocalhost() &&
106 				g_settings->getBool("enable_register_confirmation")) {
107 			promptConfirmRegistration(chosen_auth_mechanism);
108 		} else {
109 			startAuth(chosen_auth_mechanism);
110 		}
111 	} else {
112 		m_chosen_auth_mech = AUTH_MECHANISM_NONE;
113 		m_access_denied = true;
114 		m_access_denied_reason = "Unknown";
115 		m_con->Disconnect();
116 	}
117 
118 }
119 
handleCommand_AuthAccept(NetworkPacket * pkt)120 void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
121 {
122 	deleteAuthData();
123 
124 	v3f playerpos;
125 	*pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
126 		>> m_sudo_auth_methods;
127 
128 	playerpos -= v3f(0, BS / 2, 0);
129 
130 	// Set player position
131 	LocalPlayer *player = m_env.getLocalPlayer();
132 	assert(player != NULL);
133 	player->setPosition(playerpos);
134 
135 	infostream << "Client: received map seed: " << m_map_seed << std::endl;
136 	infostream << "Client: received recommended send interval "
137 					<< m_recommended_send_interval<<std::endl;
138 
139 	// Reply to server
140 	/*~ DO NOT TRANSLATE THIS LITERALLY!
141 	This is a special string which needs to contain the translation's
142 	language code (e.g. "de" for German). */
143 	std::string lang = gettext("LANG_CODE");
144 	if (lang == "LANG_CODE")
145 		lang = "";
146 
147 	NetworkPacket resp_pkt(TOSERVER_INIT2, sizeof(u16) + lang.size());
148 	resp_pkt << lang;
149 	Send(&resp_pkt);
150 
151 	m_state = LC_Init;
152 }
handleCommand_AcceptSudoMode(NetworkPacket * pkt)153 void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
154 {
155 	deleteAuthData();
156 
157 	m_password = m_new_password;
158 
159 	verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
160 
161 	// send packet to actually set the password
162 	startAuth(AUTH_MECHANISM_FIRST_SRP);
163 
164 	// reset again
165 	m_chosen_auth_mech = AUTH_MECHANISM_NONE;
166 }
handleCommand_DenySudoMode(NetworkPacket * pkt)167 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
168 {
169 	ChatMessage *chatMessage = new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
170 			L"Password change denied. Password NOT changed.");
171 	pushToChatQueue(chatMessage);
172 	// reset everything and be sad
173 	deleteAuthData();
174 }
175 
handleCommand_AccessDenied(NetworkPacket * pkt)176 void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
177 {
178 	// The server didn't like our password. Note, this needs
179 	// to be processed even if the serialisation format has
180 	// not been agreed yet, the same as TOCLIENT_INIT.
181 	m_access_denied = true;
182 	m_access_denied_reason = "Unknown";
183 
184 	if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) {
185 		// 13/03/15 Legacy code from 0.4.12 and lesser but is still used
186 		// in some places of the server code
187 		if (pkt->getSize() >= 2) {
188 			std::wstring wide_reason;
189 			*pkt >> wide_reason;
190 			m_access_denied_reason = wide_to_utf8(wide_reason);
191 		}
192 		return;
193 	}
194 
195 	if (pkt->getSize() < 1)
196 		return;
197 
198 	u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
199 	*pkt >> denyCode;
200 	if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN ||
201 			denyCode == SERVER_ACCESSDENIED_CRASH) {
202 		*pkt >> m_access_denied_reason;
203 		if (m_access_denied_reason.empty()) {
204 			m_access_denied_reason = accessDeniedStrings[denyCode];
205 		}
206 		u8 reconnect;
207 		*pkt >> reconnect;
208 		m_access_denied_reconnect = reconnect & 1;
209 	} else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
210 		*pkt >> m_access_denied_reason;
211 	} else if (denyCode == SERVER_ACCESSDENIED_TOO_MANY_USERS) {
212 		m_access_denied_reason = accessDeniedStrings[denyCode];
213 		m_access_denied_reconnect = true;
214 	} else if (denyCode < SERVER_ACCESSDENIED_MAX) {
215 		m_access_denied_reason = accessDeniedStrings[denyCode];
216 	} else {
217 		// Allow us to add new error messages to the
218 		// protocol without raising the protocol version, if we want to.
219 		// Until then (which may be never), this is outside
220 		// of the defined protocol.
221 		*pkt >> m_access_denied_reason;
222 		if (m_access_denied_reason.empty()) {
223 			m_access_denied_reason = "Unknown";
224 		}
225 	}
226 }
227 
handleCommand_RemoveNode(NetworkPacket * pkt)228 void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
229 {
230 	if (pkt->getSize() < 6)
231 		return;
232 
233 	v3s16 p;
234 	*pkt >> p;
235 	removeNode(p);
236 }
237 
handleCommand_AddNode(NetworkPacket * pkt)238 void Client::handleCommand_AddNode(NetworkPacket* pkt)
239 {
240 	if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
241 		return;
242 
243 	v3s16 p;
244 	*pkt >> p;
245 
246 	MapNode n;
247 	n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
248 
249 	bool remove_metadata = true;
250 	u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
251 	if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
252 		remove_metadata = false;
253 	}
254 
255 	addNode(p, n, remove_metadata);
256 }
257 
handleCommand_NodemetaChanged(NetworkPacket * pkt)258 void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt)
259 {
260 	if (pkt->getSize() < 1)
261 		return;
262 
263 	std::istringstream is(pkt->readLongString(), std::ios::binary);
264 	std::stringstream sstr;
265 	decompressZlib(is, sstr);
266 
267 	NodeMetadataList meta_updates_list(false);
268 	meta_updates_list.deSerialize(sstr, m_itemdef, true);
269 
270 	Map &map = m_env.getMap();
271 	for (NodeMetadataMap::const_iterator i = meta_updates_list.begin();
272 			i != meta_updates_list.end(); ++i) {
273 		v3s16 pos = i->first;
274 
275 		if (map.isValidPosition(pos) &&
276 				map.setNodeMetadata(pos, i->second))
277 			continue; // Prevent from deleting metadata
278 
279 		// Meta couldn't be set, unused metadata
280 		delete i->second;
281 	}
282 }
283 
handleCommand_BlockData(NetworkPacket * pkt)284 void Client::handleCommand_BlockData(NetworkPacket* pkt)
285 {
286 	// Ignore too small packet
287 	if (pkt->getSize() < 6)
288 		return;
289 
290 	v3s16 p;
291 	*pkt >> p;
292 
293 	std::string datastring(pkt->getString(6), pkt->getSize() - 6);
294 	std::istringstream istr(datastring, std::ios_base::binary);
295 
296 	MapSector *sector;
297 	MapBlock *block;
298 
299 	v2s16 p2d(p.X, p.Z);
300 	sector = m_env.getMap().emergeSector(p2d);
301 
302 	assert(sector->getPos() == p2d);
303 
304 	block = sector->getBlockNoCreateNoEx(p.Y);
305 	if (block) {
306 		/*
307 			Update an existing block
308 		*/
309 		block->deSerialize(istr, m_server_ser_ver, false);
310 		block->deSerializeNetworkSpecific(istr);
311 	}
312 	else {
313 		/*
314 			Create a new block
315 		*/
316 		block = new MapBlock(&m_env.getMap(), p, this);
317 		block->deSerialize(istr, m_server_ser_ver, false);
318 		block->deSerializeNetworkSpecific(istr);
319 		sector->insertBlock(block);
320 	}
321 
322 	if (m_localdb) {
323 		ServerMap::saveBlock(block, m_localdb);
324 	}
325 
326 	/*
327 		Add it to mesh update queue and set it to be acknowledged after update.
328 	*/
329 	addUpdateMeshTaskWithEdge(p, true);
330 }
331 
handleCommand_Inventory(NetworkPacket * pkt)332 void Client::handleCommand_Inventory(NetworkPacket* pkt)
333 {
334 	if (pkt->getSize() < 1)
335 		return;
336 
337 	std::string datastring(pkt->getString(0), pkt->getSize());
338 	std::istringstream is(datastring, std::ios_base::binary);
339 
340 	LocalPlayer *player = m_env.getLocalPlayer();
341 	assert(player != NULL);
342 
343 	player->inventory.deSerialize(is);
344 
345 	m_update_wielded_item = true;
346 
347 	delete m_inventory_from_server;
348 	m_inventory_from_server = new Inventory(player->inventory);
349 	m_inventory_from_server_age = 0.0;
350 }
351 
handleCommand_TimeOfDay(NetworkPacket * pkt)352 void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
353 {
354 	if (pkt->getSize() < 2)
355 		return;
356 
357 	u16 time_of_day;
358 
359 	*pkt >> time_of_day;
360 
361 	time_of_day      = time_of_day % 24000;
362 	float time_speed = 0;
363 
364 	if (pkt->getSize() >= 2 + 4) {
365 		*pkt >> time_speed;
366 	}
367 	else {
368 		// Old message; try to approximate speed of time by ourselves
369 		float time_of_day_f = (float)time_of_day / 24000.0f;
370 		float tod_diff_f = 0;
371 
372 		if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
373 			tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0f;
374 		else
375 			tod_diff_f = time_of_day_f - m_last_time_of_day_f;
376 
377 		m_last_time_of_day_f       = time_of_day_f;
378 		float time_diff            = m_time_of_day_update_timer;
379 		m_time_of_day_update_timer = 0;
380 
381 		if (m_time_of_day_set) {
382 			time_speed = (3600.0f * 24.0f) * tod_diff_f / time_diff;
383 			infostream << "Client: Measured time_of_day speed (old format): "
384 					<< time_speed << " tod_diff_f=" << tod_diff_f
385 					<< " time_diff=" << time_diff << std::endl;
386 		}
387 	}
388 
389 	// Update environment
390 	m_env.setTimeOfDay(time_of_day);
391 	m_env.setTimeOfDaySpeed(time_speed);
392 	m_time_of_day_set = true;
393 
394 	//u32 dr = m_env.getDayNightRatio();
395 	//infostream << "Client: time_of_day=" << time_of_day
396 	//		<< " time_speed=" << time_speed
397 	//		<< " dr=" << dr << std::endl;
398 }
399 
handleCommand_ChatMessage(NetworkPacket * pkt)400 void Client::handleCommand_ChatMessage(NetworkPacket *pkt)
401 {
402 	/*
403 		u8 version
404 		u8 message_type
405 		u16 sendername length
406 		wstring sendername
407 		u16 length
408 		wstring message
409 	 */
410 
411 	ChatMessage *chatMessage = new ChatMessage();
412 	u8 version, message_type;
413 	*pkt >> version >> message_type;
414 
415 	if (version != 1 || message_type >= CHATMESSAGE_TYPE_MAX) {
416 		delete chatMessage;
417 		return;
418 	}
419 
420 	u64 timestamp;
421 	*pkt >> chatMessage->sender >> chatMessage->message >> timestamp;
422 	chatMessage->timestamp = static_cast<std::time_t>(timestamp);
423 
424 	chatMessage->type = (ChatMessageType) message_type;
425 
426 	// @TODO send this to CSM using ChatMessage object
427 	if (modsLoaded() && m_script->on_receiving_message(
428 			wide_to_utf8(chatMessage->message))) {
429 		// Message was consumed by CSM and should not be handled by client
430 		delete chatMessage;
431 	} else {
432 		pushToChatQueue(chatMessage);
433 	}
434 }
435 
handleCommand_ActiveObjectRemoveAdd(NetworkPacket * pkt)436 void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
437 {
438 	/*
439 		u16 count of removed objects
440 		for all removed objects {
441 			u16 id
442 		}
443 		u16 count of added objects
444 		for all added objects {
445 			u16 id
446 			u8 type
447 			u32 initialization data length
448 			string initialization data
449 		}
450 	*/
451 
452 	try {
453 		u8 type;
454 		u16 removed_count, added_count, id;
455 
456 		// Read removed objects
457 		*pkt >> removed_count;
458 
459 		for (u16 i = 0; i < removed_count; i++) {
460 			*pkt >> id;
461 			m_env.removeActiveObject(id);
462 		}
463 
464 		// Read added objects
465 		*pkt >> added_count;
466 
467 		for (u16 i = 0; i < added_count; i++) {
468 			*pkt >> id >> type;
469 			m_env.addActiveObject(id, type, pkt->readLongString());
470 		}
471 	} catch (PacketError &e) {
472 		infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
473 				<< ". The packet is unreliable, ignoring" << std::endl;
474 	}
475 
476 	// m_activeobjects_received is false before the first
477 	// TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD packet is received
478 	m_activeobjects_received = true;
479 }
480 
handleCommand_ActiveObjectMessages(NetworkPacket * pkt)481 void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
482 {
483 	/*
484 		for all objects
485 		{
486 			u16 id
487 			u16 message length
488 			string message
489 		}
490 	*/
491 	std::string datastring(pkt->getString(0), pkt->getSize());
492 	std::istringstream is(datastring, std::ios_base::binary);
493 
494 	try {
495 		while (is.good()) {
496 			u16 id = readU16(is);
497 			if (!is.good())
498 				break;
499 
500 			std::string message = deSerializeString16(is);
501 
502 			// Pass on to the environment
503 			m_env.processActiveObjectMessage(id, message);
504 		}
505 	} catch (SerializationError &e) {
506 		errorstream << "Client::handleCommand_ActiveObjectMessages: "
507 			<< "caught SerializationError: " << e.what() << std::endl;
508 	}
509 }
510 
handleCommand_Movement(NetworkPacket * pkt)511 void Client::handleCommand_Movement(NetworkPacket* pkt)
512 {
513 	LocalPlayer *player = m_env.getLocalPlayer();
514 	assert(player != NULL);
515 
516 	float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
517 
518 	*pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
519 		>> lf >> lfs >> ls >> g;
520 
521 	player->movement_acceleration_default   = mad * BS;
522 	player->movement_acceleration_air       = maa * BS;
523 	player->movement_acceleration_fast      = maf * BS;
524 	player->movement_speed_walk             = msw * BS;
525 	player->movement_speed_crouch           = mscr * BS;
526 	player->movement_speed_fast             = msf * BS;
527 	player->movement_speed_climb            = mscl * BS;
528 	player->movement_speed_jump             = msj * BS;
529 	player->movement_liquid_fluidity        = lf * BS;
530 	player->movement_liquid_fluidity_smooth = lfs * BS;
531 	player->movement_liquid_sink            = ls * BS;
532 	player->movement_gravity                = g * BS;
533 }
534 
handleCommand_Fov(NetworkPacket * pkt)535 void Client::handleCommand_Fov(NetworkPacket *pkt)
536 {
537 	f32 fov;
538 	bool is_multiplier = false;
539 	f32 transition_time = 0.0f;
540 
541 	*pkt >> fov >> is_multiplier;
542 
543 	// Wrap transition_time extraction within a
544 	// try-catch to preserve backwards compat
545 	try {
546 		*pkt >> transition_time;
547 	} catch (PacketError &e) {};
548 
549 	LocalPlayer *player = m_env.getLocalPlayer();
550 	assert(player);
551 	player->setFov({ fov, is_multiplier, transition_time });
552 	m_camera->notifyFovChange();
553 }
554 
handleCommand_HP(NetworkPacket * pkt)555 void Client::handleCommand_HP(NetworkPacket *pkt)
556 {
557 	LocalPlayer *player = m_env.getLocalPlayer();
558 	assert(player != NULL);
559 
560 	u16 oldhp = player->hp;
561 
562 	u16 hp;
563 	*pkt >> hp;
564 
565 	player->hp = hp;
566 
567 	if (modsLoaded())
568 		m_script->on_hp_modification(hp);
569 
570 	if (hp < oldhp) {
571 		// Add to ClientEvent queue
572 		ClientEvent *event = new ClientEvent();
573 		event->type = CE_PLAYER_DAMAGE;
574 		event->player_damage.amount = oldhp - hp;
575 		m_client_event_queue.push(event);
576 	}
577 }
578 
handleCommand_Breath(NetworkPacket * pkt)579 void Client::handleCommand_Breath(NetworkPacket* pkt)
580 {
581 	LocalPlayer *player = m_env.getLocalPlayer();
582 	assert(player != NULL);
583 
584 	u16 breath;
585 
586 	*pkt >> breath;
587 
588 	player->setBreath(breath);
589 }
590 
handleCommand_MovePlayer(NetworkPacket * pkt)591 void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
592 {
593 	LocalPlayer *player = m_env.getLocalPlayer();
594 	assert(player != NULL);
595 
596 	v3f pos;
597 	f32 pitch, yaw;
598 
599 	*pkt >> pos >> pitch >> yaw;
600 
601 	player->setPosition(pos);
602 
603 	infostream << "Client got TOCLIENT_MOVE_PLAYER"
604 			<< " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
605 			<< " pitch=" << pitch
606 			<< " yaw=" << yaw
607 			<< std::endl;
608 
609 	/*
610 		Add to ClientEvent queue.
611 		This has to be sent to the main program because otherwise
612 		it would just force the pitch and yaw values to whatever
613 		the camera points to.
614 	*/
615 	ClientEvent *event = new ClientEvent();
616 	event->type = CE_PLAYER_FORCE_MOVE;
617 	event->player_force_move.pitch = pitch;
618 	event->player_force_move.yaw = yaw;
619 	m_client_event_queue.push(event);
620 }
621 
handleCommand_DeathScreen(NetworkPacket * pkt)622 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
623 {
624 	bool set_camera_point_target;
625 	v3f camera_point_target;
626 
627 	*pkt >> set_camera_point_target;
628 	*pkt >> camera_point_target;
629 
630 	ClientEvent *event = new ClientEvent();
631 	event->type                                = CE_DEATHSCREEN;
632 	event->deathscreen.set_camera_point_target = set_camera_point_target;
633 	event->deathscreen.camera_point_target_x   = camera_point_target.X;
634 	event->deathscreen.camera_point_target_y   = camera_point_target.Y;
635 	event->deathscreen.camera_point_target_z   = camera_point_target.Z;
636 	m_client_event_queue.push(event);
637 }
638 
handleCommand_AnnounceMedia(NetworkPacket * pkt)639 void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
640 {
641 	u16 num_files;
642 
643 	*pkt >> num_files;
644 
645 	infostream << "Client: Received media announcement: packet size: "
646 			<< pkt->getSize() << std::endl;
647 
648 	if (m_media_downloader == NULL ||
649 			m_media_downloader->isStarted()) {
650 		const char *problem = m_media_downloader ?
651 			"we already saw another announcement" :
652 			"all media has been received already";
653 		errorstream << "Client: Received media announcement but "
654 			<< problem << "! "
655 			<< " files=" << num_files
656 			<< " size=" << pkt->getSize() << std::endl;
657 		return;
658 	}
659 
660 	// Mesh update thread must be stopped while
661 	// updating content definitions
662 	sanity_check(!m_mesh_update_thread.isRunning());
663 
664 	for (u16 i = 0; i < num_files; i++) {
665 		std::string name, sha1_base64;
666 
667 		*pkt >> name >> sha1_base64;
668 
669 		std::string sha1_raw = base64_decode(sha1_base64);
670 		m_media_downloader->addFile(name, sha1_raw);
671 	}
672 
673 	try {
674 		std::string str;
675 
676 		*pkt >> str;
677 
678 		Strfnd sf(str);
679 		while(!sf.at_end()) {
680 			std::string baseurl = trim(sf.next(","));
681 			if (!baseurl.empty())
682 				m_media_downloader->addRemoteServer(baseurl);
683 		}
684 	}
685 	catch(SerializationError& e) {
686 		// not supported by server or turned off
687 	}
688 
689 	m_media_downloader->step(this);
690 }
691 
handleCommand_Media(NetworkPacket * pkt)692 void Client::handleCommand_Media(NetworkPacket* pkt)
693 {
694 	/*
695 		u16 command
696 		u16 total number of file bunches
697 		u16 index of this bunch
698 		u32 number of files in this bunch
699 		for each file {
700 			u16 length of name
701 			string name
702 			u32 length of data
703 			data
704 		}
705 	*/
706 	u16 num_bunches;
707 	u16 bunch_i;
708 	u32 num_files;
709 
710 	*pkt >> num_bunches >> bunch_i >> num_files;
711 
712 	infostream << "Client: Received files: bunch " << bunch_i << "/"
713 			<< num_bunches << " files=" << num_files
714 			<< " size=" << pkt->getSize() << std::endl;
715 
716 	if (num_files == 0)
717 		return;
718 
719 	if (!m_media_downloader || !m_media_downloader->isStarted()) {
720 		const char *problem = m_media_downloader ?
721 			"media has not been requested" :
722 			"all media has been received already";
723 		errorstream << "Client: Received media but "
724 			<< problem << "! "
725 			<< " bunch " << bunch_i << "/" << num_bunches
726 			<< " files=" << num_files
727 			<< " size=" << pkt->getSize() << std::endl;
728 		return;
729 	}
730 
731 	// Mesh update thread must be stopped while
732 	// updating content definitions
733 	sanity_check(!m_mesh_update_thread.isRunning());
734 
735 	for (u32 i=0; i < num_files; i++) {
736 		std::string name;
737 
738 		*pkt >> name;
739 
740 		std::string data = pkt->readLongString();
741 
742 		m_media_downloader->conventionalTransferDone(
743 				name, data, this);
744 	}
745 }
746 
handleCommand_NodeDef(NetworkPacket * pkt)747 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
748 {
749 	infostream << "Client: Received node definitions: packet size: "
750 			<< pkt->getSize() << std::endl;
751 
752 	// Mesh update thread must be stopped while
753 	// updating content definitions
754 	sanity_check(!m_mesh_update_thread.isRunning());
755 
756 	// Decompress node definitions
757 	std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
758 	std::ostringstream tmp_os;
759 	decompressZlib(tmp_is, tmp_os);
760 
761 	// Deserialize node definitions
762 	std::istringstream tmp_is2(tmp_os.str());
763 	m_nodedef->deSerialize(tmp_is2);
764 	m_nodedef_received = true;
765 }
766 
handleCommand_ItemDef(NetworkPacket * pkt)767 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
768 {
769 	infostream << "Client: Received item definitions: packet size: "
770 			<< pkt->getSize() << std::endl;
771 
772 	// Mesh update thread must be stopped while
773 	// updating content definitions
774 	sanity_check(!m_mesh_update_thread.isRunning());
775 
776 	// Decompress item definitions
777 	std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
778 	std::ostringstream tmp_os;
779 	decompressZlib(tmp_is, tmp_os);
780 
781 	// Deserialize node definitions
782 	std::istringstream tmp_is2(tmp_os.str());
783 	m_itemdef->deSerialize(tmp_is2);
784 	m_itemdef_received = true;
785 }
786 
handleCommand_PlaySound(NetworkPacket * pkt)787 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
788 {
789 	/*
790 		[0] u32 server_id
791 		[4] u16 name length
792 		[6] char name[len]
793 		[ 6 + len] f32 gain
794 		[10 + len] u8 type
795 		[11 + len] (f32 * 3) pos
796 		[23 + len] u16 object_id
797 		[25 + len] bool loop
798 		[26 + len] f32 fade
799 		[30 + len] f32 pitch
800 		[34 + len] bool ephemeral
801 	*/
802 
803 	s32 server_id;
804 	std::string name;
805 
806 	float gain;
807 	u8 type; // 0=local, 1=positional, 2=object
808 	v3f pos;
809 	u16 object_id;
810 	bool loop;
811 	float fade = 0.0f;
812 	float pitch = 1.0f;
813 	bool ephemeral = false;
814 
815 	*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
816 
817 	try {
818 		*pkt >> fade;
819 		*pkt >> pitch;
820 		*pkt >> ephemeral;
821 	} catch (PacketError &e) {};
822 
823 	// Start playing
824 	int client_id = -1;
825 	switch(type) {
826 		case 0: // local
827 			client_id = m_sound->playSound(name, loop, gain, fade, pitch);
828 			break;
829 		case 1: // positional
830 			client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
831 			break;
832 		case 2:
833 		{ // object
834 			ClientActiveObject *cao = m_env.getActiveObject(object_id);
835 			if (cao)
836 				pos = cao->getPosition();
837 			client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
838 			break;
839 		}
840 		default:
841 			break;
842 	}
843 
844 	if (client_id != -1) {
845 		// for ephemeral sounds, server_id is not meaningful
846 		if (!ephemeral) {
847 			m_sounds_server_to_client[server_id] = client_id;
848 			m_sounds_client_to_server[client_id] = server_id;
849 		}
850 		if (object_id != 0)
851 			m_sounds_to_objects[client_id] = object_id;
852 	}
853 }
854 
handleCommand_StopSound(NetworkPacket * pkt)855 void Client::handleCommand_StopSound(NetworkPacket* pkt)
856 {
857 	s32 server_id;
858 
859 	*pkt >> server_id;
860 
861 	std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
862 	if (i != m_sounds_server_to_client.end()) {
863 		int client_id = i->second;
864 		m_sound->stopSound(client_id);
865 	}
866 }
867 
handleCommand_FadeSound(NetworkPacket * pkt)868 void Client::handleCommand_FadeSound(NetworkPacket *pkt)
869 {
870 	s32 sound_id;
871 	float step;
872 	float gain;
873 
874 	*pkt >> sound_id >> step >> gain;
875 
876 	std::unordered_map<s32, int>::const_iterator i =
877 			m_sounds_server_to_client.find(sound_id);
878 
879 	if (i != m_sounds_server_to_client.end())
880 		m_sound->fadeSound(i->second, step, gain);
881 }
882 
handleCommand_Privileges(NetworkPacket * pkt)883 void Client::handleCommand_Privileges(NetworkPacket* pkt)
884 {
885 	m_privileges.clear();
886 	infostream << "Client: Privileges updated: ";
887 	u16 num_privileges;
888 
889 	*pkt >> num_privileges;
890 
891 	for (u16 i = 0; i < num_privileges; i++) {
892 		std::string priv;
893 
894 		*pkt >> priv;
895 
896 		m_privileges.insert(priv);
897 		infostream << priv << " ";
898 	}
899 	infostream << std::endl;
900 }
901 
handleCommand_InventoryFormSpec(NetworkPacket * pkt)902 void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
903 {
904 	LocalPlayer *player = m_env.getLocalPlayer();
905 	assert(player != NULL);
906 
907 	// Store formspec in LocalPlayer
908 	player->inventory_formspec = pkt->readLongString();
909 }
910 
handleCommand_DetachedInventory(NetworkPacket * pkt)911 void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
912 {
913 	std::string name;
914 	bool keep_inv = true;
915 	*pkt >> name >> keep_inv;
916 
917 	infostream << "Client: Detached inventory update: \"" << name
918 		<< "\", mode=" << (keep_inv ? "update" : "remove") << std::endl;
919 
920 	const auto &inv_it = m_detached_inventories.find(name);
921 	if (!keep_inv) {
922 		if (inv_it != m_detached_inventories.end()) {
923 			delete inv_it->second;
924 			m_detached_inventories.erase(inv_it);
925 		}
926 		return;
927 	}
928 	Inventory *inv = nullptr;
929 	if (inv_it == m_detached_inventories.end()) {
930 		inv = new Inventory(m_itemdef);
931 		m_detached_inventories[name] = inv;
932 	} else {
933 		inv = inv_it->second;
934 	}
935 
936 	u16 ignore;
937 	*pkt >> ignore; // this used to be the length of the following string, ignore it
938 
939 	std::string contents(pkt->getRemainingString(), pkt->getRemainingBytes());
940 	std::istringstream is(contents, std::ios::binary);
941 	inv->deSerialize(is);
942 }
943 
handleCommand_ShowFormSpec(NetworkPacket * pkt)944 void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt)
945 {
946 	std::string formspec = pkt->readLongString();
947 	std::string formname;
948 
949 	*pkt >> formname;
950 
951 	ClientEvent *event = new ClientEvent();
952 	event->type = CE_SHOW_FORMSPEC;
953 	// pointer is required as event is a struct only!
954 	// adding a std:string to a struct isn't possible
955 	event->show_formspec.formspec = new std::string(formspec);
956 	event->show_formspec.formname = new std::string(formname);
957 	m_client_event_queue.push(event);
958 }
959 
handleCommand_SpawnParticle(NetworkPacket * pkt)960 void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
961 {
962 	std::string datastring(pkt->getString(0), pkt->getSize());
963 	std::istringstream is(datastring, std::ios_base::binary);
964 
965 	ParticleParameters p;
966 	p.deSerialize(is, m_proto_ver);
967 
968 	ClientEvent *event = new ClientEvent();
969 	event->type           = CE_SPAWN_PARTICLE;
970 	event->spawn_particle = new ParticleParameters(p);
971 
972 	m_client_event_queue.push(event);
973 }
974 
handleCommand_AddParticleSpawner(NetworkPacket * pkt)975 void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
976 {
977 	std::string datastring(pkt->getString(0), pkt->getSize());
978 	std::istringstream is(datastring, std::ios_base::binary);
979 
980 	ParticleSpawnerParameters p;
981 	u32 server_id;
982 	u16 attached_id = 0;
983 
984 	p.amount             = readU16(is);
985 	p.time               = readF32(is);
986 	p.minpos             = readV3F32(is);
987 	p.maxpos             = readV3F32(is);
988 	p.minvel             = readV3F32(is);
989 	p.maxvel             = readV3F32(is);
990 	p.minacc             = readV3F32(is);
991 	p.maxacc             = readV3F32(is);
992 	p.minexptime         = readF32(is);
993 	p.maxexptime         = readF32(is);
994 	p.minsize            = readF32(is);
995 	p.maxsize            = readF32(is);
996 	p.collisiondetection = readU8(is);
997 	p.texture            = deSerializeString32(is);
998 
999 	server_id = readU32(is);
1000 
1001 	p.vertical = readU8(is);
1002 	p.collision_removal = readU8(is);
1003 
1004 	attached_id = readU16(is);
1005 
1006 	p.animation.deSerialize(is, m_proto_ver);
1007 	p.glow = readU8(is);
1008 	p.object_collision = readU8(is);
1009 
1010 	// This is kinda awful
1011 	do {
1012 		u16 tmp_param0 = readU16(is);
1013 		if (is.eof())
1014 			break;
1015 		p.node.param0 = tmp_param0;
1016 		p.node.param2 = readU8(is);
1017 		p.node_tile   = readU8(is);
1018 	} while (0);
1019 
1020 	auto event = new ClientEvent();
1021 	event->type                            = CE_ADD_PARTICLESPAWNER;
1022 	event->add_particlespawner.p           = new ParticleSpawnerParameters(p);
1023 	event->add_particlespawner.attached_id = attached_id;
1024 	event->add_particlespawner.id          = server_id;
1025 
1026 	m_client_event_queue.push(event);
1027 }
1028 
1029 
handleCommand_DeleteParticleSpawner(NetworkPacket * pkt)1030 void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
1031 {
1032 	u32 server_id;
1033 	*pkt >> server_id;
1034 
1035 	ClientEvent *event = new ClientEvent();
1036 	event->type = CE_DELETE_PARTICLESPAWNER;
1037 	event->delete_particlespawner.id = server_id;
1038 
1039 	m_client_event_queue.push(event);
1040 }
1041 
handleCommand_HudAdd(NetworkPacket * pkt)1042 void Client::handleCommand_HudAdd(NetworkPacket* pkt)
1043 {
1044 	std::string datastring(pkt->getString(0), pkt->getSize());
1045 	std::istringstream is(datastring, std::ios_base::binary);
1046 
1047 	u32 server_id;
1048 	u8 type;
1049 	v2f pos;
1050 	std::string name;
1051 	v2f scale;
1052 	std::string text;
1053 	u32 number;
1054 	u32 item;
1055 	u32 dir;
1056 	v2f align;
1057 	v2f offset;
1058 	v3f world_pos;
1059 	v2s32 size;
1060 	s16 z_index = 0;
1061 	std::string text2;
1062 
1063 	*pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item
1064 		>> dir >> align >> offset;
1065 	try {
1066 		*pkt >> world_pos;
1067 		*pkt >> size;
1068 		*pkt >> z_index;
1069 		*pkt >> text2;
1070 	} catch(PacketError &e) {};
1071 
1072 	ClientEvent *event = new ClientEvent();
1073 	event->type             = CE_HUDADD;
1074 	event->hudadd.server_id = server_id;
1075 	event->hudadd.type      = type;
1076 	event->hudadd.pos       = new v2f(pos);
1077 	event->hudadd.name      = new std::string(name);
1078 	event->hudadd.scale     = new v2f(scale);
1079 	event->hudadd.text      = new std::string(text);
1080 	event->hudadd.number    = number;
1081 	event->hudadd.item      = item;
1082 	event->hudadd.dir       = dir;
1083 	event->hudadd.align     = new v2f(align);
1084 	event->hudadd.offset    = new v2f(offset);
1085 	event->hudadd.world_pos = new v3f(world_pos);
1086 	event->hudadd.size      = new v2s32(size);
1087 	event->hudadd.z_index   = z_index;
1088 	event->hudadd.text2     = new std::string(text2);
1089 	m_client_event_queue.push(event);
1090 }
1091 
handleCommand_HudRemove(NetworkPacket * pkt)1092 void Client::handleCommand_HudRemove(NetworkPacket* pkt)
1093 {
1094 	u32 server_id;
1095 
1096 	*pkt >> server_id;
1097 
1098 	ClientEvent *event = new ClientEvent();
1099 	event->type     = CE_HUDRM;
1100 	event->hudrm.id = server_id;
1101 	m_client_event_queue.push(event);
1102 }
1103 
handleCommand_HudChange(NetworkPacket * pkt)1104 void Client::handleCommand_HudChange(NetworkPacket* pkt)
1105 {
1106 	std::string sdata;
1107 	v2f v2fdata;
1108 	v3f v3fdata;
1109 	u32 intdata = 0;
1110 	v2s32 v2s32data;
1111 	u32 server_id;
1112 	u8 stat;
1113 
1114 	*pkt >> server_id >> stat;
1115 
1116 	if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1117 		stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1118 		*pkt >> v2fdata;
1119 	else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT || stat == HUD_STAT_TEXT2)
1120 		*pkt >> sdata;
1121 	else if (stat == HUD_STAT_WORLD_POS)
1122 		*pkt >> v3fdata;
1123 	else if (stat == HUD_STAT_SIZE )
1124 		*pkt >> v2s32data;
1125 	else
1126 		*pkt >> intdata;
1127 
1128 	ClientEvent *event = new ClientEvent();
1129 	event->type              = CE_HUDCHANGE;
1130 	event->hudchange.id      = server_id;
1131 	event->hudchange.stat    = (HudElementStat)stat;
1132 	event->hudchange.v2fdata = new v2f(v2fdata);
1133 	event->hudchange.v3fdata = new v3f(v3fdata);
1134 	event->hudchange.sdata   = new std::string(sdata);
1135 	event->hudchange.data    = intdata;
1136 	event->hudchange.v2s32data = new v2s32(v2s32data);
1137 	m_client_event_queue.push(event);
1138 }
1139 
handleCommand_HudSetFlags(NetworkPacket * pkt)1140 void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
1141 {
1142 	u32 flags, mask;
1143 
1144 	*pkt >> flags >> mask;
1145 
1146 	LocalPlayer *player = m_env.getLocalPlayer();
1147 	assert(player != NULL);
1148 
1149 	bool was_minimap_visible = player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE;
1150 	bool was_minimap_radar_visible = player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE;
1151 
1152 	player->hud_flags &= ~mask;
1153 	player->hud_flags |= flags;
1154 
1155 	m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1156 	bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1157 
1158 	// Not so satisying code to keep compatibility with old fixed mode system
1159 	// -->
1160 
1161 	// Hide minimap if it has been disabled by the server
1162 	if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible)
1163 		// defers a minimap update, therefore only call it if really
1164 		// needed, by checking that minimap was visible before
1165 		m_minimap->setModeIndex(0);
1166 
1167 	// If radar has been disabled, try to find a non radar mode or fall back to 0
1168 	if (m_minimap && m_minimap_radar_disabled_by_server
1169 			&& was_minimap_radar_visible) {
1170 		while (m_minimap->getModeIndex() > 0 &&
1171 				m_minimap->getModeDef().type == MINIMAP_TYPE_RADAR)
1172 			m_minimap->nextMode();
1173 	}
1174 	// <--
1175 	// End of 'not so satifying code'
1176 }
1177 
handleCommand_HudSetParam(NetworkPacket * pkt)1178 void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
1179 {
1180 	u16 param; std::string value;
1181 
1182 	*pkt >> param >> value;
1183 
1184 	LocalPlayer *player = m_env.getLocalPlayer();
1185 	assert(player != NULL);
1186 
1187 	if (param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1188 		s32 hotbar_itemcount = readS32((u8*) value.c_str());
1189 		if (hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1190 			player->hud_hotbar_itemcount = hotbar_itemcount;
1191 	}
1192 	else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1193 		player->hotbar_image = value;
1194 	}
1195 	else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1196 		player->hotbar_selected_image = value;
1197 	}
1198 }
1199 
handleCommand_HudSetSky(NetworkPacket * pkt)1200 void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
1201 {
1202 	if (m_proto_ver < 39) {
1203 		// Handle Protocol 38 and below servers with old set_sky,
1204 		// ensuring the classic look is kept.
1205 		std::string datastring(pkt->getString(0), pkt->getSize());
1206 		std::istringstream is(datastring, std::ios_base::binary);
1207 
1208 		SkyboxParams skybox;
1209 		skybox.bgcolor = video::SColor(readARGB8(is));
1210 		skybox.type = std::string(deSerializeString16(is));
1211 		u16 count = readU16(is);
1212 
1213 		for (size_t i = 0; i < count; i++)
1214 			skybox.textures.emplace_back(deSerializeString16(is));
1215 
1216 		skybox.clouds = true;
1217 		try {
1218 			skybox.clouds = readU8(is);
1219 		} catch (...) {}
1220 
1221 		// Use default skybox settings:
1222 		SkyboxDefaults sky_defaults;
1223 		SunParams sun = sky_defaults.getSunDefaults();
1224 		MoonParams moon = sky_defaults.getMoonDefaults();
1225 		StarParams stars = sky_defaults.getStarDefaults();
1226 
1227 		// Fix for "regular" skies, as color isn't kept:
1228 		if (skybox.type == "regular") {
1229 			skybox.sky_color = sky_defaults.getSkyColorDefaults();
1230 			skybox.fog_tint_type = "default";
1231 			skybox.fog_moon_tint = video::SColor(255, 255, 255, 255);
1232 			skybox.fog_sun_tint = video::SColor(255, 255, 255, 255);
1233 		}
1234 		else {
1235 			sun.visible = false;
1236 			sun.sunrise_visible = false;
1237 			moon.visible = false;
1238 			stars.visible = false;
1239 		}
1240 
1241 		// Skybox, sun, moon and stars ClientEvents:
1242 		ClientEvent *sky_event = new ClientEvent();
1243 		sky_event->type = CE_SET_SKY;
1244 		sky_event->set_sky = new SkyboxParams(skybox);
1245 		m_client_event_queue.push(sky_event);
1246 
1247 		ClientEvent *sun_event = new ClientEvent();
1248 		sun_event->type = CE_SET_SUN;
1249 		sun_event->sun_params = new SunParams(sun);
1250 		m_client_event_queue.push(sun_event);
1251 
1252 		ClientEvent *moon_event = new ClientEvent();
1253 		moon_event->type = CE_SET_MOON;
1254 		moon_event->moon_params = new MoonParams(moon);
1255 		m_client_event_queue.push(moon_event);
1256 
1257 		ClientEvent *star_event = new ClientEvent();
1258 		star_event->type = CE_SET_STARS;
1259 		star_event->star_params = new StarParams(stars);
1260 		m_client_event_queue.push(star_event);
1261 	} else {
1262 		SkyboxParams skybox;
1263 		u16 texture_count;
1264 		std::string texture;
1265 
1266 		*pkt >> skybox.bgcolor >> skybox.type >> skybox.clouds >>
1267 			skybox.fog_sun_tint >> skybox.fog_moon_tint >> skybox.fog_tint_type;
1268 
1269 		if (skybox.type == "skybox") {
1270 			*pkt >> texture_count;
1271 			for (int i = 0; i < texture_count; i++) {
1272 				*pkt >> texture;
1273 				skybox.textures.emplace_back(texture);
1274 			}
1275 		}
1276 		else if (skybox.type == "regular") {
1277 			*pkt >> skybox.sky_color.day_sky >> skybox.sky_color.day_horizon
1278 				>> skybox.sky_color.dawn_sky >> skybox.sky_color.dawn_horizon
1279 				>> skybox.sky_color.night_sky >> skybox.sky_color.night_horizon
1280 				>> skybox.sky_color.indoors;
1281 		}
1282 
1283 		ClientEvent *event = new ClientEvent();
1284 		event->type = CE_SET_SKY;
1285 		event->set_sky = new SkyboxParams(skybox);
1286 		m_client_event_queue.push(event);
1287 	}
1288 }
1289 
handleCommand_HudSetSun(NetworkPacket * pkt)1290 void Client::handleCommand_HudSetSun(NetworkPacket *pkt)
1291 {
1292 	SunParams sun;
1293 
1294 	*pkt >> sun.visible >> sun.texture>> sun.tonemap
1295 		>> sun.sunrise >> sun.sunrise_visible >> sun.scale;
1296 
1297 	ClientEvent *event = new ClientEvent();
1298 	event->type        = CE_SET_SUN;
1299 	event->sun_params  = new SunParams(sun);
1300 	m_client_event_queue.push(event);
1301 }
1302 
handleCommand_HudSetMoon(NetworkPacket * pkt)1303 void Client::handleCommand_HudSetMoon(NetworkPacket *pkt)
1304 {
1305 	MoonParams moon;
1306 
1307 	*pkt >> moon.visible >> moon.texture
1308 		>> moon.tonemap >> moon.scale;
1309 
1310 	ClientEvent *event = new ClientEvent();
1311 	event->type        = CE_SET_MOON;
1312 	event->moon_params = new MoonParams(moon);
1313 	m_client_event_queue.push(event);
1314 }
1315 
handleCommand_HudSetStars(NetworkPacket * pkt)1316 void Client::handleCommand_HudSetStars(NetworkPacket *pkt)
1317 {
1318 	StarParams stars;
1319 
1320 	*pkt >> stars.visible >> stars.count
1321 		>> stars.starcolor >> stars.scale;
1322 
1323 	ClientEvent *event = new ClientEvent();
1324 	event->type        = CE_SET_STARS;
1325 	event->star_params = new StarParams(stars);
1326 
1327 	m_client_event_queue.push(event);
1328 }
1329 
handleCommand_CloudParams(NetworkPacket * pkt)1330 void Client::handleCommand_CloudParams(NetworkPacket* pkt)
1331 {
1332 	f32 density;
1333 	video::SColor color_bright;
1334 	video::SColor color_ambient;
1335 	f32 height;
1336 	f32 thickness;
1337 	v2f speed;
1338 
1339 	*pkt >> density >> color_bright >> color_ambient
1340 			>> height >> thickness >> speed;
1341 
1342 	ClientEvent *event = new ClientEvent();
1343 	event->type                       = CE_CLOUD_PARAMS;
1344 	event->cloud_params.density       = density;
1345 	// use the underlying u32 representation, because we can't
1346 	// use struct members with constructors here, and this way
1347 	// we avoid using new() and delete() for no good reason
1348 	event->cloud_params.color_bright  = color_bright.color;
1349 	event->cloud_params.color_ambient = color_ambient.color;
1350 	event->cloud_params.height        = height;
1351 	event->cloud_params.thickness     = thickness;
1352 	// same here: deconstruct to skip constructor
1353 	event->cloud_params.speed_x       = speed.X;
1354 	event->cloud_params.speed_y       = speed.Y;
1355 	m_client_event_queue.push(event);
1356 }
1357 
handleCommand_OverrideDayNightRatio(NetworkPacket * pkt)1358 void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt)
1359 {
1360 	bool do_override;
1361 	u16 day_night_ratio_u;
1362 
1363 	*pkt >> do_override >> day_night_ratio_u;
1364 
1365 	float day_night_ratio_f = (float)day_night_ratio_u / 65536;
1366 
1367 	ClientEvent *event = new ClientEvent();
1368 	event->type                                 = CE_OVERRIDE_DAY_NIGHT_RATIO;
1369 	event->override_day_night_ratio.do_override = do_override;
1370 	event->override_day_night_ratio.ratio_f     = day_night_ratio_f;
1371 	m_client_event_queue.push(event);
1372 }
1373 
handleCommand_LocalPlayerAnimations(NetworkPacket * pkt)1374 void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
1375 {
1376 	LocalPlayer *player = m_env.getLocalPlayer();
1377 	assert(player != NULL);
1378 
1379 	*pkt >> player->local_animations[0];
1380 	*pkt >> player->local_animations[1];
1381 	*pkt >> player->local_animations[2];
1382 	*pkt >> player->local_animations[3];
1383 	*pkt >> player->local_animation_speed;
1384 }
1385 
handleCommand_EyeOffset(NetworkPacket * pkt)1386 void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
1387 {
1388 	LocalPlayer *player = m_env.getLocalPlayer();
1389 	assert(player != NULL);
1390 
1391 	*pkt >> player->eye_offset_first >> player->eye_offset_third;
1392 }
1393 
handleCommand_UpdatePlayerList(NetworkPacket * pkt)1394 void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt)
1395 {
1396 	u8 type;
1397 	u16 num_players;
1398 	*pkt >> type >> num_players;
1399 	PlayerListModifer notice_type = (PlayerListModifer) type;
1400 
1401 	for (u16 i = 0; i < num_players; i++) {
1402 		std::string name;
1403 		*pkt >> name;
1404 		switch (notice_type) {
1405 		case PLAYER_LIST_INIT:
1406 		case PLAYER_LIST_ADD:
1407 			m_env.addPlayerName(name);
1408 			continue;
1409 		case PLAYER_LIST_REMOVE:
1410 			m_env.removePlayerName(name);
1411 			continue;
1412 		}
1413 	}
1414 }
1415 
handleCommand_SrpBytesSandB(NetworkPacket * pkt)1416 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
1417 {
1418 	if (m_chosen_auth_mech != AUTH_MECHANISM_SRP &&
1419 			m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
1420 		errorstream << "Client: Received SRP S_B login message,"
1421 			<< " but wasn't supposed to (chosen_mech="
1422 			<< m_chosen_auth_mech << ")." << std::endl;
1423 		return;
1424 	}
1425 
1426 	char *bytes_M = 0;
1427 	size_t len_M = 0;
1428 	SRPUser *usr = (SRPUser *) m_auth_data;
1429 	std::string s;
1430 	std::string B;
1431 	*pkt >> s >> B;
1432 
1433 	infostream << "Client: Received TOCLIENT_SRP_BYTES_S_B." << std::endl;
1434 
1435 	srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
1436 		(const unsigned char *) B.c_str(), B.size(),
1437 		(unsigned char **) &bytes_M, &len_M);
1438 
1439 	if ( !bytes_M ) {
1440 		errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
1441 		return;
1442 	}
1443 
1444 	NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
1445 	resp_pkt << std::string(bytes_M, len_M);
1446 	Send(&resp_pkt);
1447 }
1448 
handleCommand_FormspecPrepend(NetworkPacket * pkt)1449 void Client::handleCommand_FormspecPrepend(NetworkPacket *pkt)
1450 {
1451 	LocalPlayer *player = m_env.getLocalPlayer();
1452 	assert(player != NULL);
1453 
1454 	// Store formspec in LocalPlayer
1455 	*pkt >> player->formspec_prepend;
1456 }
1457 
handleCommand_CSMRestrictionFlags(NetworkPacket * pkt)1458 void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
1459 {
1460 	*pkt >> m_csm_restriction_flags >> m_csm_restriction_noderange;
1461 
1462 	// Restrictions were received -> load mods if it's enabled
1463 	// Note: this should be moved after mods receptions from server instead
1464 	loadMods();
1465 }
1466 
handleCommand_PlayerSpeed(NetworkPacket * pkt)1467 void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
1468 {
1469 	v3f added_vel;
1470 
1471 	*pkt >> added_vel;
1472 
1473 	LocalPlayer *player = m_env.getLocalPlayer();
1474 	assert(player != NULL);
1475 	player->addVelocity(added_vel);
1476 }
1477 
handleCommand_MediaPush(NetworkPacket * pkt)1478 void Client::handleCommand_MediaPush(NetworkPacket *pkt)
1479 {
1480 	std::string raw_hash, filename, filedata;
1481 	bool cached;
1482 
1483 	*pkt >> raw_hash >> filename >> cached;
1484 	filedata = pkt->readLongString();
1485 
1486 	if (raw_hash.size() != 20 || filedata.empty() || filename.empty() ||
1487 			!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
1488 		throw PacketError("Illegal filename, data or hash");
1489 	}
1490 
1491 	verbosestream << "Server pushes media file \"" << filename << "\" with "
1492 		<< filedata.size() << " bytes of data (cached=" << cached
1493 		<< ")" << std::endl;
1494 
1495 	if (m_media_pushed_files.count(filename) != 0) {
1496 		// Silently ignore for synchronization purposes
1497 		return;
1498 	}
1499 
1500 	// Compute and check checksum of data
1501 	std::string computed_hash;
1502 	{
1503 		SHA1 ctx;
1504 		ctx.addBytes(filedata.c_str(), filedata.size());
1505 		unsigned char *buf = ctx.getDigest();
1506 		computed_hash.assign((char*) buf, 20);
1507 		free(buf);
1508 	}
1509 	if (raw_hash != computed_hash) {
1510 		verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
1511 		return;
1512 	}
1513 
1514 	// Actually load media
1515 	loadMedia(filedata, filename, true);
1516 	m_media_pushed_files.insert(filename);
1517 
1518 	// Cache file for the next time when this client joins the same server
1519 	if (cached)
1520 		clientMediaUpdateCache(raw_hash, filedata);
1521 }
1522 
1523 /*
1524  * Mod channels
1525  */
1526 
handleCommand_ModChannelMsg(NetworkPacket * pkt)1527 void Client::handleCommand_ModChannelMsg(NetworkPacket *pkt)
1528 {
1529 	std::string channel_name, sender, channel_msg;
1530 	*pkt >> channel_name >> sender >> channel_msg;
1531 
1532 	verbosestream << "Mod channel message received from server " << pkt->getPeerId()
1533 		<< " on channel " << channel_name << ". sender: `" << sender << "`, message: "
1534 		<< channel_msg << std::endl;
1535 
1536 	if (!m_modchannel_mgr->channelRegistered(channel_name)) {
1537 		verbosestream << "Server sent us messages on unregistered channel "
1538 			<< channel_name << ", ignoring." << std::endl;
1539 		return;
1540 	}
1541 
1542 	m_script->on_modchannel_message(channel_name, sender, channel_msg);
1543 }
1544 
handleCommand_ModChannelSignal(NetworkPacket * pkt)1545 void Client::handleCommand_ModChannelSignal(NetworkPacket *pkt)
1546 {
1547 	u8 signal_tmp;
1548 	ModChannelSignal signal;
1549 	std::string channel;
1550 
1551 	*pkt >> signal_tmp >> channel;
1552 
1553 	signal = (ModChannelSignal)signal_tmp;
1554 
1555 	bool valid_signal = true;
1556 	// @TODO: send Signal to Lua API
1557 	switch (signal) {
1558 		case MODCHANNEL_SIGNAL_JOIN_OK:
1559 			m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
1560 			infostream << "Server ack our mod channel join on channel `" << channel
1561 				<< "`, joining." << std::endl;
1562 			break;
1563 		case MODCHANNEL_SIGNAL_JOIN_FAILURE:
1564 			// Unable to join, remove channel
1565 			m_modchannel_mgr->leaveChannel(channel, 0);
1566 			infostream << "Server refused our mod channel join on channel `" << channel
1567 				<< "`" << std::endl;
1568 			break;
1569 		case MODCHANNEL_SIGNAL_LEAVE_OK:
1570 #ifndef NDEBUG
1571 			infostream << "Server ack our mod channel leave on channel " << channel
1572 				<< "`, leaving." << std::endl;
1573 #endif
1574 			break;
1575 		case MODCHANNEL_SIGNAL_LEAVE_FAILURE:
1576 			infostream << "Server refused our mod channel leave on channel `" << channel
1577 				<< "`" << std::endl;
1578 			break;
1579 		case MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED:
1580 #ifndef NDEBUG
1581 			// Generally unused, but ensure we don't do an implementation error
1582 			infostream << "Server tells us we sent a message on channel `" << channel
1583 				<< "` but we are not registered. Message was dropped." << std::endl;
1584 #endif
1585 			break;
1586 		case MODCHANNEL_SIGNAL_SET_STATE: {
1587 			u8 state;
1588 			*pkt >> state;
1589 
1590 			if (state == MODCHANNEL_STATE_INIT || state >= MODCHANNEL_STATE_MAX) {
1591 				infostream << "Received wrong channel state " << state
1592 						<< ", ignoring." << std::endl;
1593 				return;
1594 			}
1595 
1596 			m_modchannel_mgr->setChannelState(channel, (ModChannelState) state);
1597 			infostream << "Server sets mod channel `" << channel
1598 					<< "` in read-only mode." << std::endl;
1599 			break;
1600 		}
1601 		default:
1602 #ifndef NDEBUG
1603 			warningstream << "Received unhandled mod channel signal ID "
1604 				<< signal << ", ignoring." << std::endl;
1605 #endif
1606 			valid_signal = false;
1607 			break;
1608 	}
1609 
1610 	// If signal is valid, forward it to client side mods
1611 	if (valid_signal)
1612 		m_script->on_modchannel_signal(channel, signal);
1613 }
1614 
handleCommand_MinimapModes(NetworkPacket * pkt)1615 void Client::handleCommand_MinimapModes(NetworkPacket *pkt)
1616 {
1617 	u16 count; // modes
1618 	u16 mode;  // wanted current mode index after change
1619 
1620 	*pkt >> count >> mode;
1621 
1622 	if (m_minimap)
1623 		m_minimap->clearModes();
1624 
1625 	for (size_t index = 0; index < count; index++) {
1626 		u16 type;
1627 		std::string label;
1628 		u16 size;
1629 		std::string texture;
1630 		u16 scale;
1631 
1632 		*pkt >> type >> label >> size >> texture >> scale;
1633 
1634 		if (m_minimap)
1635 			m_minimap->addMode(MinimapType(type), size, label, texture, scale);
1636 	}
1637 
1638 	if (m_minimap)
1639 		m_minimap->setModeIndex(mode);
1640 }
1641