void Server::sendRequestedMedia(u16 peer_id,
		const std::vector<std::string> &tosend)
{
	DSTACK(FUNCTION_NAME);

	verbosestream<<"Server::sendRequestedMedia(): "
			<<"Sending files to client"<<std::endl;

	/* Read files */
	// TODO: optimize
	MediaData media_data;
	u32 size = 0;

	for(auto i = tosend.begin();
			i != tosend.end(); ++i) {
		const std::string &name = *i;

		if(m_media.find(name) == m_media.end()) {
			errorstream<<"Server::sendRequestedMedia(): Client asked for "
					<<"unknown file \""<<(name)<<"\""<<std::endl;
			continue;
		}

		//TODO get path + name
		std::string tpath = m_media[name].path;

		// Read data
		std::ifstream fis(tpath.c_str(), std::ios_base::binary);
		if(fis.good() == false){
			errorstream<<"Server::sendRequestedMedia(): Could not open \""
					<<tpath<<"\" for reading"<<std::endl;
			continue;
		}
		std::string contents;
		fis.seekg(0, std::ios::end);
		contents.resize(fis.tellg());
		fis.seekg(0, std::ios::beg);
		fis.read(&contents[0], contents.size());
		media_data.push_back(std::make_pair(name, contents));
		size += contents.size();
		if (size > 0xffff) {
			MSGPACK_PACKET_INIT(TOCLIENT_MEDIA, 1);
			PACK(TOCLIENT_MEDIA_MEDIA, media_data);
			m_clients.send(peer_id, 2, buffer, true);
			media_data.clear();
			size = 0;
		}
	}

	if (!media_data.empty()) {
		MSGPACK_PACKET_INIT(TOCLIENT_MEDIA, 1);
		PACK(TOCLIENT_MEDIA_MEDIA, media_data);
		m_clients.send(peer_id, 2, buffer, true);
	}
}
void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
{
	MSGPACK_PACKET_INIT(TOCLIENT_HUDCHANGE, 3);
	PACK(TOCLIENT_HUDCHANGE_ID, id);
	PACK(TOCLIENT_HUDCHANGE_STAT, (int)stat);

	switch (stat) {
		case HUD_STAT_POS:
		case HUD_STAT_SCALE:
		case HUD_STAT_ALIGN:
		case HUD_STAT_OFFSET:
			PACK(TOCLIENT_HUDCHANGE_V2F, *(v2f*)value);
			break;
		case HUD_STAT_NAME:
		case HUD_STAT_TEXT:
			PACK(TOCLIENT_HUDCHANGE_STRING, *(std::string*)value);
			break;
		case HUD_STAT_WORLD_POS:
			PACK(TOCLIENT_HUDCHANGE_V3F, *(v3f*)value);
			break;
		case HUD_STAT_SIZE:
			PACK(TOCLIENT_HUDCHANGE_V2S32, *(v2s32 *)value);
			break;
		case HUD_STAT_NUMBER:
		case HUD_STAT_ITEM:
		case HUD_STAT_DIR:
		default:
			PACK(TOCLIENT_HUDCHANGE_U32, *(u32*)value);
			break;
	}

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
{
	if(m_detached_inventories.count(name) == 0){
		errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
		return;
	}
	Inventory *inv = m_detached_inventories[name];

	std::ostringstream os(std::ios_base::binary);
	inv->serialize(os);

	MSGPACK_PACKET_INIT(TOCLIENT_DETACHED_INVENTORY, 2);
	PACK(TOCLIENT_DETACHED_INVENTORY_NAME, name);
	PACK(TOCLIENT_DETACHED_INVENTORY_DATA, os.str());

	if (peer_id != PEER_ID_INEXISTENT)
	{
		// Send as reliable
		m_clients.send(peer_id, 0, buffer, true);
	}
	else
	{
		m_clients.sendToAll(0,buffer,true);
	}
}
// Adds a ParticleSpawner on peer with peer_id
void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
	v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
	float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
{
	DSTACK(FUNCTION_NAME);

	MSGPACK_PACKET_INIT(TOCLIENT_ADD_PARTICLESPAWNER, 16);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_AMOUNT, amount);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_SPAWNTIME, spawntime);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MINPOS, minpos);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MAXPOS, maxpos);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MINVEL, minvel);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MAXVEL, maxvel);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MINACC, minacc);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MAXACC, maxacc);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MINEXPTIME, minexptime);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MAXEXPTIME, maxexptime);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MINSIZE, minsize);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_MAXSIZE, maxsize);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_COLLISIONDETECTION, collisiondetection);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_TEXTURE, texture);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_VERTICAL, vertical);
	PACK(TOCLIENT_ADD_PARTICLESPAWNER_ID, id);

	if (peer_id != PEER_ID_INEXISTENT)
	{
		// Send as reliable
		m_clients.send(peer_id, 0, buffer, true);
	}
	else {
		m_clients.sendToAll(0,buffer,true);
	}
}
void Client::interact(u8 action, const PointedThing& pointed)
{
	if(m_state != LC_Ready) {
		infostream << "Client::interact() "
				"cancelled (not connected)"
				<< std::endl;
		return;
	}

	/*
		[0] u16 command
		[2] u8 action
		[3] u16 item
		[5] u32 length of the next item
		[9] serialized PointedThing
		actions:
		0: start digging (from undersurface) or use
		1: stop digging (all parameters ignored)
		2: digging completed
		3: place block or item (to abovesurface)
		4: use item
	*/
	MSGPACK_PACKET_INIT(TOSERVER_INTERACT, 3);
	PACK(TOSERVER_INTERACT_ACTION, action);
	PACK(TOSERVER_INTERACT_ITEM, getPlayerItem());
	PACK(TOSERVER_INTERACT_POINTED_THING, pointed);

	// Send as reliable
	Send(0, buffer, true);
}
void Client::sendChatMessage(const std::string &message)
{
	MSGPACK_PACKET_INIT(TOSERVER_CHAT_MESSAGE, 1);
	PACK(TOSERVER_CHAT_MESSAGE_DATA, message);
	// Send as reliable
	Send(0, buffer, true);
}
void Client::sendRemovedSounds(std::vector<s32> &soundList)
{
	MSGPACK_PACKET_INIT(TOSERVER_REMOVED_SOUNDS, 1);
	PACK(TOSERVER_REMOVED_SOUNDS_IDS, soundList);
	// Send as reliable
	Send(1, buffer, true);
}
void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
	std::vector<u16> *far_players, float far_d_nodes)
{
	float maxd = far_d_nodes*BS;
	v3f p_f = intToFloat(p, BS);

	// Create packet
	MSGPACK_PACKET_INIT(TOCLIENT_REMOVENODE, 1);
	PACK(TOCLIENT_REMOVENODE_POS, p);

	std::vector<u16> clients = m_clients.getClientIDs();
	for(auto
		i = clients.begin();
		i != clients.end(); ++i)
	{
		if(far_players) {
			// Get player
			Player *player = m_env->getPlayer(*i);
			if(player) {
				// If player is far away, only set modified blocks not sent
				v3f player_pos = player->getPosition();
				if(player_pos.getDistanceFrom(p_f) > maxd) {
					far_players->push_back(*i);
					continue;
				}
			}
		}

		// Send as reliable
		m_clients.send(*i, 0, buffer, true);
	}
}
void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
{
	DSTACK(FUNCTION_NAME);
	bool reliable = 1;

	g_profiler->add("Connection: blocks sent", 1);

	MSGPACK_PACKET_INIT(TOCLIENT_BLOCKDATA, 8);
	PACK(TOCLIENT_BLOCKDATA_POS, block->getPos());

	std::ostringstream os(std::ios_base::binary);

	auto client = m_clients.getClient(peer_id);
	if (!client)
		return;
	block->serialize(os, ver, false, client->net_proto_version_fm >= 1);
	PACK(TOCLIENT_BLOCKDATA_DATA, os.str());

	PACK(TOCLIENT_BLOCKDATA_HEAT, (s16)(block->heat + block->heat_add));
	PACK(TOCLIENT_BLOCKDATA_HUMIDITY, (s16)(block->humidity + block->humidity_add));
	PACK(TOCLIENT_BLOCKDATA_STEP, (s8)1);
	PACK(TOCLIENT_BLOCKDATA_CONTENT_ONLY, block->content_only);
	PACK(TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM1, block->content_only_param1);
	PACK(TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM2, block->content_only_param2);

	//MutexAutoLock lock(m_env_mutex);
	/*
		Send packet
	*/
	m_clients.send(peer_id, 2, buffer, reliable);
}
// Spawns a particle on peer with peer_id
void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
				float expirationtime, float size, bool collisiondetection,
				bool vertical, std::string texture)
{
	DSTACK(FUNCTION_NAME);

	MSGPACK_PACKET_INIT(TOCLIENT_SPAWN_PARTICLE, 8);
	PACK(TOCLIENT_SPAWN_PARTICLE_POS, pos);
	PACK(TOCLIENT_SPAWN_PARTICLE_VELOCITY, velocity);
	PACK(TOCLIENT_SPAWN_PARTICLE_ACCELERATION, acceleration);
	PACK(TOCLIENT_SPAWN_PARTICLE_EXPIRATIONTIME, expirationtime);
	PACK(TOCLIENT_SPAWN_PARTICLE_SIZE, size);
	PACK(TOCLIENT_SPAWN_PARTICLE_COLLISIONDETECTION, collisiondetection);
	PACK(TOCLIENT_SPAWN_PARTICLE_VERTICAL, vertical);
	PACK(TOCLIENT_SPAWN_PARTICLE_TEXTURE, texture);

	if (peer_id != PEER_ID_INEXISTENT)
	{
	// Send as reliable
		m_clients.send(peer_id, 0, buffer, true);
	}
	else
	{
		m_clients.sendToAll(0,buffer,true);
	}
}
void Client::sendRespawn()
{
	DSTACK(FUNCTION_NAME);

	MSGPACK_PACKET_INIT(TOSERVER_RESPAWN, 0);
	// Send as reliable
	Send(0, buffer, true);
}
void Client::sendDeletedBlocks(std::vector<v3s16> &blocks)
{

	MSGPACK_PACKET_INIT(TOSERVER_DELETEDBLOCKS, 1);
	PACK(TOSERVER_DELETEDBLOCKS_DATA, blocks);

	m_con.Send(PEER_ID_SERVER, 2, buffer, true);
}
void Client::sendInventoryFields(const std::string &formname,
		const std::map<std::string, std::string> &fields)
{
	MSGPACK_PACKET_INIT(TOSERVER_INVENTORY_FIELDS, 2);
	PACK(TOSERVER_INVENTORY_FIELDS_FORMNAME, formname);
	PACK(TOSERVER_INVENTORY_FIELDS_DATA, fields);
	Send(0, buffer, true);
}
void Server::SendActiveObjectMessages(u16 peer_id, const ActiveObjectMessages &datas, bool reliable)
{
	MSGPACK_PACKET_INIT(TOCLIENT_ACTIVE_OBJECT_MESSAGES, 1);
	PACK(TOCLIENT_ACTIVE_OBJECT_MESSAGES_MESSAGES, datas);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, reliable);
}
void Server::SendBreath(u16 peer_id, u16 breath)
{
	DSTACK(FUNCTION_NAME);
	MSGPACK_PACKET_INIT(TOCLIENT_BREATH, 1);
	PACK(TOCLIENT_BREATH_BREATH, breath);
	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
{
	MSGPACK_PACKET_INIT(TOCLIENT_EYE_OFFSET, 2);
	PACK(TOCLIENT_EYE_OFFSET_FIRST, first);
	PACK(TOCLIENT_EYE_OFFSET_THIRD, third);
	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Client::sendDamage(u8 damage)
{
	DSTACK(FUNCTION_NAME);
	MSGPACK_PACKET_INIT(TOSERVER_DAMAGE, 1);
	PACK(TOSERVER_DAMAGE_VALUE, damage);

	// Send as reliable
	Send(0, buffer, true);
}
void Server::SendHUDRemove(u16 peer_id, u32 id)
{
	MSGPACK_PACKET_INIT(TOCLIENT_HUDRM, 1);
	PACK(TOCLIENT_HUDRM_ID, id);

	// Send as reliable

	m_clients.send(peer_id, 1, buffer, true);
}
void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
{
	MSGPACK_PACKET_INIT(TOCLIENT_HUD_SET_PARAM, 2);
	PACK(TOCLIENT_HUD_SET_PARAM_ID, param);
	PACK(TOCLIENT_HUD_SET_PARAM_VALUE, value);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Client::sendBreath(u16 breath)
{
	DSTACK(FUNCTION_NAME);

	MSGPACK_PACKET_INIT(TOSERVER_BREATH, 1);
	PACK(TOSERVER_BREATH_VALUE, breath);
	// Send as reliable
	Send(0, buffer, true);
}
void Client::received_media()
{
	// notify server we received everything
	MSGPACK_PACKET_INIT(TOSERVER_RECEIVED_MEDIA, 0);
	// Send as reliable
	Send(1, buffer, true);
	infostream<<"Client: Notifying server that we received all media"
			<<std::endl;
}
void Client::request_media(const std::vector<std::string> &file_requests)
{
	MSGPACK_PACKET_INIT(TOSERVER_REQUEST_MEDIA, 1);
	PACK(TOSERVER_REQUEST_MEDIA_FILES, file_requests);

	// Send as reliable
	Send(1, buffer, true);
	infostream<<"Client: Sending media request list to server ("
			<<file_requests.size()<<" files)"<<std::endl;
}
void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
		float ratio)
{
	MSGPACK_PACKET_INIT(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO, 2);
	PACK(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_DO, do_override);
	PACK(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_VALUE, ratio);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
		const std::map<std::string, std::string> &fields)
{
	MSGPACK_PACKET_INIT(TOSERVER_NODEMETA_FIELDS, 3);
	PACK(TOSERVER_NODEMETA_FIELDS_POS, p);
	PACK(TOSERVER_NODEMETA_FIELDS_FORMNAME, formname);
	PACK(TOSERVER_NODEMETA_FIELDS_DATA, fields);
	// Send as reliable
	Send(0, buffer, true);
}
void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason, bool reconnect)
{
	DSTACK(FUNCTION_NAME);
	MSGPACK_PACKET_INIT(TOCLIENT_ACCESS_DENIED_LEGACY, 3);
	PACK(TOCLIENT_ACCESS_DENIED_CUSTOM_STRING, custom_reason);
	PACK(TOCLIENT_ACCESS_DENIED_REASON, (int)reason);
	PACK(TOCLIENT_ACCESS_DENIED_RECONNECT, reconnect);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Server::SendHP(u16 peer_id, u8 hp)
{
	DSTACK(FUNCTION_NAME);
	std::ostringstream os(std::ios_base::binary);

	MSGPACK_PACKET_INIT(TOCLIENT_HP, 1);
	PACK(TOCLIENT_HP_HP, hp);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
		const std::string &type, const std::vector<std::string> &params)
{
	MSGPACK_PACKET_INIT(TOCLIENT_SET_SKY, 3);
	PACK(TOCLIENT_SET_SKY_COLOR, bgcolor);
	PACK(TOCLIENT_SET_SKY_TYPE, type);
	PACK(TOCLIENT_SET_SKY_PARAMS, params);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
{
	MSGPACK_PACKET_INIT(TOCLIENT_HUD_SET_FLAGS, 2);
	//////////////////////////// compatibility code to be removed //////////////
	// ?? flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
	PACK(TOCLIENT_HUD_SET_FLAGS_FLAGS, flags);
	PACK(TOCLIENT_HUD_SET_FLAGS_MASK, mask);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}
void Client::sendDrawControl() {
	MSGPACK_PACKET_INIT(TOSERVER_DRAWCONTROL, 5);
	const auto & draw_control = m_env.getClientMap().getControl();
	PACK(TOSERVER_DRAWCONTROL_WANTED_RANGE, (u32)draw_control.wanted_range);
	PACK(TOSERVER_DRAWCONTROL_RANGE_ALL, (u32)draw_control.range_all);
	PACK(TOSERVER_DRAWCONTROL_FARMESH, (u8)draw_control.farmesh);
	PACK(TOSERVER_DRAWCONTROL_FOV, draw_control.fov);
	PACK(TOSERVER_DRAWCONTROL_BLOCK_OVERFLOW, false /*draw_control.block_overflow*/);

	Send(0, buffer, false);
}
void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
		v3f camera_point_target)
{
	DSTACK(FUNCTION_NAME);

	MSGPACK_PACKET_INIT(TOCLIENT_DEATHSCREEN, 2);
	PACK(TOCLIENT_DEATHSCREEN_SET_CAMERA, set_camera_point_target);
	PACK(TOCLIENT_DEATHSCREEN_CAMERA_POINT, camera_point_target);

	// Send as reliable
	m_clients.send(peer_id, 0, buffer, true);
}