diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 753291cba44412a774d842ecd16c6f321d44d962..8e3ae95abf4b2768a767d2d152e625269eb7dbc5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -445,6 +445,7 @@ set(common_SRCS
 	porting.cpp
 	profiler.cpp
 	quicktune.cpp
+	remoteplayer.cpp
 	rollback.cpp
 	rollback_interface.cpp
 	serialization.cpp
diff --git a/src/clientiface.cpp b/src/clientiface.cpp
index fbfc16770118c0fe452add5232b3078b23d6afb4..d78cf1c53bf63724632795d7f785f370d59ff623 100644
--- a/src/clientiface.cpp
+++ b/src/clientiface.cpp
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clientiface.h"
 #include "util/numeric.h"
 #include "util/mathconstants.h"
-#include "player.h"
+#include "remoteplayer.h"
 #include "settings.h"
 #include "mapblock.h"
 #include "network/connection.h"
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 1664f59931068b794d4d3068c4c84526708ef6ec..5d3ed38bc28f5b690ac30e116af3f65d62cb0bdf 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serialization.h" // For compressZlib
 #include "tool.h" // For ToolCapabilities
 #include "gamedef.h"
-#include "player.h"
+#include "remoteplayer.h"
 #include "server.h"
 #include "scripting_game.h"
 #include "genericobject.h"
@@ -391,7 +391,7 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
 					(*ii).second.X, (*ii).second.Y)); // m_bone_position.size
 		}
 		os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
-		for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin(); 
+		for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin();
 				(ii != m_attachment_child_ids.end()); ++ii) {
 			if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) {
 				os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), obj->getClientInitializationData(protocol_version)));
@@ -880,7 +880,7 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
 				m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak,
 				m_physics_override_sneak_glitch)); // 5
 		os << serializeLongString(gob_cmd_update_nametag_attributes(m_prop.nametag_color)); // 6 (GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES) : Deprecated, for backwards compatibility only.
-		for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin(); 
+		for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin();
 				ii != m_attachment_child_ids.end(); ++ii) {
 			if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) {
 				os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), obj->getClientInitializationData(protocol_version)));
diff --git a/src/content_sao.h b/src/content_sao.h
index 341ebb5da51489b0364508c892988c924739c697..76a3a37da03cb96bcd2cad142db17f7cda5e7386 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "serverobject.h"
 #include "itemgroup.h"
-#include "player.h"
 #include "object_properties.h"
 
 /*
@@ -157,6 +156,8 @@ class LagPool
 	}
 };
 
+class RemotePlayer;
+
 class PlayerSAO : public ServerActiveObject
 {
 public:
@@ -231,7 +232,7 @@ class PlayerSAO : public ServerActiveObject
 
 	void disconnected();
 
-	RemotePlayer* getPlayer() { return m_player; }
+	RemotePlayer *getPlayer() { return m_player; }
 	u16 getPeerID() const { return m_peer_id; }
 
 	// Cheat prevention
diff --git a/src/environment.cpp b/src/environment.cpp
index 514aa918a0aaafc5fc0f556a42541eabe3471997..ff43ac516242f35125e94e37dbaf1e96bfbf2457 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -2705,7 +2705,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
 		}
 		object->setId(new_id);
 	}
-	if(!isFreeClientActiveObjectId(object->getId(), m_active_objects)) {
+	if (!isFreeClientActiveObjectId(object->getId(), m_active_objects)) {
 		infostream<<"ClientEnvironment::addActiveObject(): "
 				<<"id is not free ("<<object->getId()<<")"<<std::endl;
 		delete object;
diff --git a/src/environment.h b/src/environment.h
index 7ed38ad5dae2dbcb22f819cbb3cd918a95ee69f6..f19708ad7e22346fa3e378729e6642b366ba3dc9 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -377,7 +377,7 @@ class ServerEnvironment : public Environment
 		Find out what new objects have been removed from
 		inside a radius around a position
 	*/
-	void getRemovedActiveObjects(RemotePlayer* player, s16 radius,
+	void getRemovedActiveObjects(RemotePlayer *player, s16 radius,
 			s16 player_radius,
 			std::set<u16> &current_objects,
 			std::queue<u16> &removed_objects);
diff --git a/src/localplayer.h b/src/localplayer.h
index 182b51d4d5b2c0144a3c069875c187ced576af34..9d43128aab8ca57b4aa2e288d24d06b360fc4f83 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -28,6 +28,7 @@ class Client;
 class Environment;
 class GenericCAO;
 class ClientActiveObject;
+class IGameDef;
 
 enum LocalPlayerAnimations {NO_ANIM, WALK_ANIM, DIG_ANIM, WD_ANIM};  // no local animation, walking, digging, both
 
diff --git a/src/player.cpp b/src/player.cpp
index c0d36713431b5e04fef6821423a77a02da1e6e49..fa82a79f43b70cc60cde80eac33bb27a78c2ee53 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -19,15 +19,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "player.h"
 
-#include <fstream>
 #include "threading/mutex_auto_lock.h"
 #include "util/numeric.h"
 #include "hud.h"
 #include "constants.h"
 #include "gamedef.h"
 #include "settings.h"
-#include "content_sao.h"
-#include "filesys.h"
 #include "log.h"
 #include "porting.h"  // strlcpy
 
@@ -143,206 +140,3 @@ void Player::clearHud()
 		hud.pop_back();
 	}
 }
-
-/*
-	RemotePlayer
-*/
-// static config cache for remoteplayer
-bool RemotePlayer::m_setting_cache_loaded = false;
-float RemotePlayer::m_setting_chat_message_limit_per_10sec = 0.0f;
-u16 RemotePlayer::m_setting_chat_message_limit_trigger_kick = 0;
-
-RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef):
-	Player(name, idef),
-	protocol_version(0),
-	m_sao(NULL),
-	m_dirty(false),
-	m_last_chat_message_sent(time(NULL)),
-	m_chat_message_allowance(5.0f),
-	m_message_rate_overhead(0),
-	hud_hotbar_image(""),
-	hud_hotbar_selected_image("")
-{
-	if (!RemotePlayer::m_setting_cache_loaded) {
-		RemotePlayer::m_setting_chat_message_limit_per_10sec =
-				g_settings->getFloat("chat_message_limit_per_10sec");
-		RemotePlayer::m_setting_chat_message_limit_trigger_kick =
-				g_settings->getU16("chat_message_limit_trigger_kick");
-		RemotePlayer::m_setting_cache_loaded = true;
-	}
-	movement_acceleration_default   = g_settings->getFloat("movement_acceleration_default")   * BS;
-	movement_acceleration_air       = g_settings->getFloat("movement_acceleration_air")       * BS;
-	movement_acceleration_fast      = g_settings->getFloat("movement_acceleration_fast")      * BS;
-	movement_speed_walk             = g_settings->getFloat("movement_speed_walk")             * BS;
-	movement_speed_crouch           = g_settings->getFloat("movement_speed_crouch")           * BS;
-	movement_speed_fast             = g_settings->getFloat("movement_speed_fast")             * BS;
-	movement_speed_climb            = g_settings->getFloat("movement_speed_climb")            * BS;
-	movement_speed_jump             = g_settings->getFloat("movement_speed_jump")             * BS;
-	movement_liquid_fluidity        = g_settings->getFloat("movement_liquid_fluidity")        * BS;
-	movement_liquid_fluidity_smooth = g_settings->getFloat("movement_liquid_fluidity_smooth") * BS;
-	movement_liquid_sink            = g_settings->getFloat("movement_liquid_sink")            * BS;
-	movement_gravity                = g_settings->getFloat("movement_gravity")                * BS;
-}
-
-void RemotePlayer::save(std::string savedir, IGameDef *gamedef)
-{
-	/*
-	 * We have to open all possible player files in the players directory
-	 * and check their player names because some file systems are not
-	 * case-sensitive and player names are case-sensitive.
-	 */
-
-	// A player to deserialize files into to check their names
-	RemotePlayer testplayer("", gamedef->idef());
-
-	savedir += DIR_DELIM;
-	std::string path = savedir + m_name;
-	for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
-		if (!fs::PathExists(path)) {
-			// Open file and serialize
-			std::ostringstream ss(std::ios_base::binary);
-			serialize(ss);
-			if (!fs::safeWriteToFile(path, ss.str())) {
-				infostream << "Failed to write " << path << std::endl;
-			}
-			setModified(false);
-			return;
-		}
-		// Open file and deserialize
-		std::ifstream is(path.c_str(), std::ios_base::binary);
-		if (!is.good()) {
-			infostream << "Failed to open " << path << std::endl;
-			return;
-		}
-		testplayer.deSerialize(is, path);
-		is.close();
-		if (strcmp(testplayer.getName(), m_name) == 0) {
-			// Open file and serialize
-			std::ostringstream ss(std::ios_base::binary);
-			serialize(ss);
-			if (!fs::safeWriteToFile(path, ss.str())) {
-				infostream << "Failed to write " << path << std::endl;
-			}
-			setModified(false);
-			return;
-		}
-		path = savedir + m_name + itos(i);
-	}
-
-	infostream << "Didn't find free file for player " << m_name << std::endl;
-	return;
-}
-
-void RemotePlayer::deSerialize(std::istream &is, const std::string &playername)
-{
-	Settings args;
-
-	if (!args.parseConfigLines(is, "PlayerArgsEnd")) {
-		throw SerializationError("PlayerArgsEnd of player " +
-								 playername + " not found!");
-	}
-
-	m_dirty = true;
-	//args.getS32("version"); // Version field value not used
-	std::string name = args.get("name");
-	strlcpy(m_name, name.c_str(), PLAYERNAME_SIZE);
-	setPitch(args.getFloat("pitch"));
-	setYaw(args.getFloat("yaw"));
-	setPosition(args.getV3F("position"));
-	try{
-		hp = args.getS32("hp");
-	}catch(SettingNotFoundException &e) {
-		hp = PLAYER_MAX_HP;
-	}
-	try{
-		m_breath = args.getS32("breath");
-	}catch(SettingNotFoundException &e) {
-		m_breath = PLAYER_MAX_BREATH;
-	}
-
-	inventory.deSerialize(is);
-
-	if(inventory.getList("craftpreview") == NULL) {
-		// Convert players without craftpreview
-		inventory.addList("craftpreview", 1);
-
-		bool craftresult_is_preview = true;
-		if(args.exists("craftresult_is_preview"))
-			craftresult_is_preview = args.getBool("craftresult_is_preview");
-		if(craftresult_is_preview)
-		{
-			// Clear craftresult
-			inventory.getList("craftresult")->changeItem(0, ItemStack());
-		}
-	}
-}
-
-void RemotePlayer::serialize(std::ostream &os)
-{
-	// Utilize a Settings object for storing values
-	Settings args;
-	args.setS32("version", 1);
-	args.set("name", m_name);
-	//args.set("password", m_password);
-	args.setFloat("pitch", m_pitch);
-	args.setFloat("yaw", m_yaw);
-	args.setV3F("position", m_position);
-	args.setS32("hp", hp);
-	args.setS32("breath", m_breath);
-
-	args.writeLines(os);
-
-	os<<"PlayerArgsEnd\n";
-
-	inventory.serialize(os);
-}
-
-void RemotePlayer::setPosition(const v3f &position)
-{
-	if (position != m_position)
-		m_dirty = true;
-
-	Player::setPosition(position);
-	if(m_sao)
-		m_sao->setBasePosition(position);
-}
-
-const RemotePlayerChatResult RemotePlayer::canSendChatMessage()
-{
-	// Rate limit messages
-	u32 now = time(NULL);
-	float time_passed = now - m_last_chat_message_sent;
-	m_last_chat_message_sent = now;
-
-	// If this feature is disabled
-	if (m_setting_chat_message_limit_per_10sec <= 0.0) {
-		return RPLAYER_CHATRESULT_OK;
-	}
-
-	m_chat_message_allowance += time_passed * (m_setting_chat_message_limit_per_10sec / 8.0f);
-	if (m_chat_message_allowance > m_setting_chat_message_limit_per_10sec) {
-		m_chat_message_allowance = m_setting_chat_message_limit_per_10sec;
-	}
-
-	if (m_chat_message_allowance < 1.0f) {
-		infostream << "Player " << m_name
-				<< " chat limited due to excessive message amount." << std::endl;
-
-		// Kick player if flooding is too intensive
-		m_message_rate_overhead++;
-		if (m_message_rate_overhead > RemotePlayer::m_setting_chat_message_limit_trigger_kick) {
-			return RPLAYER_CHATRESULT_KICK;
-		}
-
-		return RPLAYER_CHATRESULT_FLOODING;
-	}
-
-	// Reinit message overhead
-	if (m_message_rate_overhead > 0) {
-		m_message_rate_overhead = 0;
-	}
-
-	m_chat_message_allowance -= 1.0f;
-	return RPLAYER_CHATRESULT_OK;
-}
-
diff --git a/src/player.h b/src/player.h
index 1980a86a3b9f6bda0510c7ebc49672caaede1fd8..3c945b100eb56033ba04a23ac68eb85fa5bd24fb 100644
--- a/src/player.h
+++ b/src/player.h
@@ -99,9 +99,7 @@ struct PlayerControl
 };
 
 class Map;
-class IGameDef;
 struct CollisionInfo;
-class PlayerSAO;
 struct HudElement;
 class Environment;
 
@@ -258,152 +256,5 @@ class Player
 	Mutex m_mutex;
 };
 
-enum RemotePlayerChatResult {
-	RPLAYER_CHATRESULT_OK,
-	RPLAYER_CHATRESULT_FLOODING,
-	RPLAYER_CHATRESULT_KICK,
-};
-/*
-	Player on the server
-*/
-class RemotePlayer : public Player
-{
-public:
-	RemotePlayer(const char *name, IItemDefManager *idef);
-	virtual ~RemotePlayer() {}
-
-	void save(std::string savedir, IGameDef *gamedef);
-	void deSerialize(std::istream &is, const std::string &playername);
-
-	PlayerSAO *getPlayerSAO() { return m_sao; }
-	void setPlayerSAO(PlayerSAO *sao) { m_sao = sao; }
-	void setPosition(const v3f &position);
-
-	const RemotePlayerChatResult canSendChatMessage();
-
-	void setHotbarItemcount(s32 hotbar_itemcount)
-	{
-		hud_hotbar_itemcount = hotbar_itemcount;
-	}
-
-	s32 getHotbarItemcount() const { return hud_hotbar_itemcount; }
-
-	void overrideDayNightRatio(bool do_override, float ratio)
-	{
-		m_day_night_ratio_do_override = do_override;
-		m_day_night_ratio = ratio;
-	}
-
-	void getDayNightRatio(bool *do_override, float *ratio)
-	{
-		*do_override = m_day_night_ratio_do_override;
-		*ratio = m_day_night_ratio;
-	}
-
-	// Use a function, if isDead can be defined by other conditions
-	bool isDead() const { return hp == 0; }
-
-	void setHotbarImage(const std::string &name)
-	{
-		hud_hotbar_image = name;
-	}
-
-	std::string getHotbarImage() const
-	{
-		return hud_hotbar_image;
-	}
-
-	void setHotbarSelectedImage(const std::string &name)
-	{
-		hud_hotbar_selected_image = name;
-	}
-
-	const std::string &getHotbarSelectedImage() const
-	{
-		return hud_hotbar_selected_image;
-	}
-
-	// Deprecated
-	f32 getRadPitchDep() const { return -1.0 * m_pitch * core::DEGTORAD; }
-
-	// Deprecated
-	f32 getRadYawDep() const { return (m_yaw + 90.) * core::DEGTORAD; }
-
-	void setSky(const video::SColor &bgcolor, const std::string &type,
-				const std::vector<std::string> &params)
-	{
-		m_sky_bgcolor = bgcolor;
-		m_sky_type = type;
-		m_sky_params = params;
-	}
-
-	void getSky(video::SColor *bgcolor, std::string *type,
-				std::vector<std::string> *params)
-	{
-		*bgcolor = m_sky_bgcolor;
-		*type = m_sky_type;
-		*params = m_sky_params;
-	}
-
-	bool checkModified() const { return m_dirty || inventory.checkModified(); }
-
-	void setModified(const bool x)
-	{
-		m_dirty = x;
-		if (!x)
-			inventory.setModified(x);
-	}
-
-	virtual void setBreath(u16 breath)
-	{
-		if (breath != m_breath)
-			m_dirty = true;
-		Player::setBreath(breath);
-	}
-
-	virtual void setPitch(f32 pitch)
-	{
-		if (pitch != m_pitch)
-			m_dirty = true;
-		Player::setPitch(pitch);
-	}
-
-	virtual void setYaw(f32 yaw)
-	{
-		if (yaw != m_yaw)
-			m_dirty = true;
-		Player::setYaw(yaw);
-	}
-
-	u16 protocol_version;
-private:
-	/*
-		serialize() writes a bunch of text that can contain
-		any characters except a '\0', and such an ending that
-		deSerialize stops reading exactly at the right point.
-	*/
-	void serialize(std::ostream &os);
-
-	PlayerSAO *m_sao;
-	bool m_dirty;
-
-	static bool m_setting_cache_loaded;
-	static float m_setting_chat_message_limit_per_10sec;
-	static u16 m_setting_chat_message_limit_trigger_kick;
-
-	u32 m_last_chat_message_sent;
-	float m_chat_message_allowance;
-	u16 m_message_rate_overhead;
-
-	bool m_day_night_ratio_do_override;
-	float m_day_night_ratio;
-	std::string hud_hotbar_image;
-	std::string hud_hotbar_selected_image;
-
-	std::string m_sky_type;
-	video::SColor m_sky_bgcolor;
-	std::vector<std::string> m_sky_params;
-};
-
 #endif
 
diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f64d1d690897aeee4234923f755716ffc3920eae
--- /dev/null
+++ b/src/remoteplayer.cpp
@@ -0,0 +1,230 @@
+/*
+Minetest
+Copyright (C) 2010-2016 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2014-2016 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "remoteplayer.h"
+#include "content_sao.h"
+#include "filesys.h"
+#include "gamedef.h"
+#include "porting.h"  // strlcpy
+#include "settings.h"
+
+
+/*
+	RemotePlayer
+*/
+// static config cache for remoteplayer
+bool RemotePlayer::m_setting_cache_loaded = false;
+float RemotePlayer::m_setting_chat_message_limit_per_10sec = 0.0f;
+u16 RemotePlayer::m_setting_chat_message_limit_trigger_kick = 0;
+
+RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef):
+	Player(name, idef),
+	protocol_version(0),
+	m_sao(NULL),
+	m_dirty(false),
+	m_last_chat_message_sent(time(NULL)),
+	m_chat_message_allowance(5.0f),
+	m_message_rate_overhead(0),
+	hud_hotbar_image(""),
+	hud_hotbar_selected_image("")
+{
+	if (!RemotePlayer::m_setting_cache_loaded) {
+		RemotePlayer::m_setting_chat_message_limit_per_10sec =
+			g_settings->getFloat("chat_message_limit_per_10sec");
+		RemotePlayer::m_setting_chat_message_limit_trigger_kick =
+			g_settings->getU16("chat_message_limit_trigger_kick");
+		RemotePlayer::m_setting_cache_loaded = true;
+	}
+	movement_acceleration_default   = g_settings->getFloat("movement_acceleration_default")   * BS;
+	movement_acceleration_air       = g_settings->getFloat("movement_acceleration_air")       * BS;
+	movement_acceleration_fast      = g_settings->getFloat("movement_acceleration_fast")      * BS;
+	movement_speed_walk             = g_settings->getFloat("movement_speed_walk")             * BS;
+	movement_speed_crouch           = g_settings->getFloat("movement_speed_crouch")           * BS;
+	movement_speed_fast             = g_settings->getFloat("movement_speed_fast")             * BS;
+	movement_speed_climb            = g_settings->getFloat("movement_speed_climb")            * BS;
+	movement_speed_jump             = g_settings->getFloat("movement_speed_jump")             * BS;
+	movement_liquid_fluidity        = g_settings->getFloat("movement_liquid_fluidity")        * BS;
+	movement_liquid_fluidity_smooth = g_settings->getFloat("movement_liquid_fluidity_smooth") * BS;
+	movement_liquid_sink            = g_settings->getFloat("movement_liquid_sink")            * BS;
+	movement_gravity                = g_settings->getFloat("movement_gravity")                * BS;
+}
+
+void RemotePlayer::save(std::string savedir, IGameDef *gamedef)
+{
+	/*
+	 * We have to open all possible player files in the players directory
+	 * and check their player names because some file systems are not
+	 * case-sensitive and player names are case-sensitive.
+	 */
+
+	// A player to deserialize files into to check their names
+	RemotePlayer testplayer("", gamedef->idef());
+
+	savedir += DIR_DELIM;
+	std::string path = savedir + m_name;
+	for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
+		if (!fs::PathExists(path)) {
+			// Open file and serialize
+			std::ostringstream ss(std::ios_base::binary);
+			serialize(ss);
+			if (!fs::safeWriteToFile(path, ss.str())) {
+				infostream << "Failed to write " << path << std::endl;
+			}
+			setModified(false);
+			return;
+		}
+		// Open file and deserialize
+		std::ifstream is(path.c_str(), std::ios_base::binary);
+		if (!is.good()) {
+			infostream << "Failed to open " << path << std::endl;
+			return;
+		}
+		testplayer.deSerialize(is, path);
+		is.close();
+		if (strcmp(testplayer.getName(), m_name) == 0) {
+			// Open file and serialize
+			std::ostringstream ss(std::ios_base::binary);
+			serialize(ss);
+			if (!fs::safeWriteToFile(path, ss.str())) {
+				infostream << "Failed to write " << path << std::endl;
+			}
+			setModified(false);
+			return;
+		}
+		path = savedir + m_name + itos(i);
+	}
+
+	infostream << "Didn't find free file for player " << m_name << std::endl;
+	return;
+}
+
+void RemotePlayer::deSerialize(std::istream &is, const std::string &playername)
+{
+	Settings args;
+
+	if (!args.parseConfigLines(is, "PlayerArgsEnd")) {
+		throw SerializationError("PlayerArgsEnd of player " +
+								 playername + " not found!");
+	}
+
+	m_dirty = true;
+	//args.getS32("version"); // Version field value not used
+	std::string name = args.get("name");
+	strlcpy(m_name, name.c_str(), PLAYERNAME_SIZE);
+	setPitch(args.getFloat("pitch"));
+	setYaw(args.getFloat("yaw"));
+	setPosition(args.getV3F("position"));
+	try {
+		hp = args.getS32("hp");
+	} catch(SettingNotFoundException &e) {
+		hp = PLAYER_MAX_HP;
+	}
+
+	try {
+		m_breath = args.getS32("breath");
+	} catch(SettingNotFoundException &e) {
+		m_breath = PLAYER_MAX_BREATH;
+	}
+
+	inventory.deSerialize(is);
+
+	if(inventory.getList("craftpreview") == NULL) {
+		// Convert players without craftpreview
+		inventory.addList("craftpreview", 1);
+
+		bool craftresult_is_preview = true;
+		if(args.exists("craftresult_is_preview"))
+			craftresult_is_preview = args.getBool("craftresult_is_preview");
+		if(craftresult_is_preview)
+		{
+			// Clear craftresult
+			inventory.getList("craftresult")->changeItem(0, ItemStack());
+		}
+	}
+}
+
+void RemotePlayer::serialize(std::ostream &os)
+{
+	// Utilize a Settings object for storing values
+	Settings args;
+	args.setS32("version", 1);
+	args.set("name", m_name);
+	//args.set("password", m_password);
+	args.setFloat("pitch", m_pitch);
+	args.setFloat("yaw", m_yaw);
+	args.setV3F("position", m_position);
+	args.setS32("hp", hp);
+	args.setS32("breath", m_breath);
+
+	args.writeLines(os);
+
+	os<<"PlayerArgsEnd\n";
+
+	inventory.serialize(os);
+}
+
+void RemotePlayer::setPosition(const v3f &position)
+{
+	if (position != m_position)
+		m_dirty = true;
+
+	Player::setPosition(position);
+	if(m_sao)
+		m_sao->setBasePosition(position);
+}
+
+const RemotePlayerChatResult RemotePlayer::canSendChatMessage()
+{
+	// Rate limit messages
+	u32 now = time(NULL);
+	float time_passed = now - m_last_chat_message_sent;
+	m_last_chat_message_sent = now;
+
+	// If this feature is disabled
+	if (m_setting_chat_message_limit_per_10sec <= 0.0) {
+		return RPLAYER_CHATRESULT_OK;
+	}
+
+	m_chat_message_allowance += time_passed * (m_setting_chat_message_limit_per_10sec / 8.0f);
+	if (m_chat_message_allowance > m_setting_chat_message_limit_per_10sec) {
+		m_chat_message_allowance = m_setting_chat_message_limit_per_10sec;
+	}
+
+	if (m_chat_message_allowance < 1.0f) {
+		infostream << "Player " << m_name
+				<< " chat limited due to excessive message amount." << std::endl;
+
+		// Kick player if flooding is too intensive
+		m_message_rate_overhead++;
+		if (m_message_rate_overhead > RemotePlayer::m_setting_chat_message_limit_trigger_kick) {
+			return RPLAYER_CHATRESULT_KICK;
+		}
+
+		return RPLAYER_CHATRESULT_FLOODING;
+	}
+
+	// Reinit message overhead
+	if (m_message_rate_overhead > 0) {
+		m_message_rate_overhead = 0;
+	}
+
+	m_chat_message_allowance -= 1.0f;
+	return RPLAYER_CHATRESULT_OK;
+}
diff --git a/src/remoteplayer.h b/src/remoteplayer.h
new file mode 100644
index 0000000000000000000000000000000000000000..f6c70b0e93eab3ea693f4c08f83df16623035804
--- /dev/null
+++ b/src/remoteplayer.h
@@ -0,0 +1,175 @@
+/*
+Minetest
+Copyright (C) 2010-2016 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2014-2016 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef REMOTEPLAYER_HEADER
+#define REMOTEPLAYER_HEADER
+
+#include "player.h"
+
+class PlayerSAO;
+
+enum RemotePlayerChatResult {
+	RPLAYER_CHATRESULT_OK,
+	RPLAYER_CHATRESULT_FLOODING,
+	RPLAYER_CHATRESULT_KICK,
+};
+/*
+	Player on the server
+*/
+class RemotePlayer : public Player
+{
+public:
+	RemotePlayer(const char *name, IItemDefManager *idef);
+	virtual ~RemotePlayer() {}
+
+	void save(std::string savedir, IGameDef *gamedef);
+	void deSerialize(std::istream &is, const std::string &playername);
+
+	PlayerSAO *getPlayerSAO() { return m_sao; }
+	void setPlayerSAO(PlayerSAO *sao) { m_sao = sao; }
+	void setPosition(const v3f &position);
+
+	const RemotePlayerChatResult canSendChatMessage();
+
+	void setHotbarItemcount(s32 hotbar_itemcount)
+	{
+		hud_hotbar_itemcount = hotbar_itemcount;
+	}
+
+	s32 getHotbarItemcount() const { return hud_hotbar_itemcount; }
+
+	void overrideDayNightRatio(bool do_override, float ratio)
+	{
+		m_day_night_ratio_do_override = do_override;
+		m_day_night_ratio = ratio;
+	}
+
+	void getDayNightRatio(bool *do_override, float *ratio)
+	{
+		*do_override = m_day_night_ratio_do_override;
+		*ratio = m_day_night_ratio;
+	}
+
+	// Use a function, if isDead can be defined by other conditions
+	bool isDead() const { return hp == 0; }
+
+	void setHotbarImage(const std::string &name)
+	{
+		hud_hotbar_image = name;
+	}
+
+	std::string getHotbarImage() const
+	{
+		return hud_hotbar_image;
+	}
+
+	void setHotbarSelectedImage(const std::string &name)
+	{
+		hud_hotbar_selected_image = name;
+	}
+
+	const std::string &getHotbarSelectedImage() const
+	{
+		return hud_hotbar_selected_image;
+	}
+
+	// Deprecated
+	f32 getRadPitchDep() const { return -1.0 * m_pitch * core::DEGTORAD; }
+
+	// Deprecated
+	f32 getRadYawDep() const { return (m_yaw + 90.) * core::DEGTORAD; }
+
+	void setSky(const video::SColor &bgcolor, const std::string &type,
+				const std::vector<std::string> &params)
+	{
+		m_sky_bgcolor = bgcolor;
+		m_sky_type = type;
+		m_sky_params = params;
+	}
+
+	void getSky(video::SColor *bgcolor, std::string *type,
+				std::vector<std::string> *params)
+	{
+		*bgcolor = m_sky_bgcolor;
+		*type = m_sky_type;
+		*params = m_sky_params;
+	}
+
+	bool checkModified() const { return m_dirty || inventory.checkModified(); }
+
+	void setModified(const bool x)
+	{
+		m_dirty = x;
+		if (!x)
+			inventory.setModified(x);
+	}
+
+	virtual void setBreath(u16 breath)
+	{
+		if (breath != m_breath)
+			m_dirty = true;
+		Player::setBreath(breath);
+	}
+
+	virtual void setPitch(f32 pitch)
+	{
+		if (pitch != m_pitch)
+			m_dirty = true;
+		Player::setPitch(pitch);
+	}
+
+	virtual void setYaw(f32 yaw)
+	{
+		if (yaw != m_yaw)
+			m_dirty = true;
+		Player::setYaw(yaw);
+	}
+
+	u16 protocol_version;
+private:
+	/*
+		serialize() writes a bunch of text that can contain
+		any characters except a '\0', and such an ending that
+		deSerialize stops reading exactly at the right point.
+	*/
+	void serialize(std::ostream &os);
+
+	PlayerSAO *m_sao;
+	bool m_dirty;
+
+	static bool m_setting_cache_loaded;
+	static float m_setting_chat_message_limit_per_10sec;
+	static u16 m_setting_chat_message_limit_trigger_kick;
+
+	u32 m_last_chat_message_sent;
+	float m_chat_message_allowance;
+	u16 m_message_rate_overhead;
+
+	bool m_day_night_ratio_do_override;
+	float m_day_night_ratio;
+	std::string hud_hotbar_image;
+	std::string hud_hotbar_selected_image;
+
+	std::string m_sky_type;
+	video::SColor m_sky_bgcolor;
+	std::vector<std::string> m_sky_params;
+};
+
+#endif
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index a1f83919ce0c99661d0c6254e40c69b0ce986a06..bb352e429cd853530b2aa9a06169ef86042546ba 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -107,7 +107,7 @@ PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
 	return (PlayerSAO*)obj;
 }
 
-RemotePlayer* ObjectRef::getplayer(ObjectRef *ref)
+RemotePlayer *ObjectRef::getplayer(ObjectRef *ref)
 {
 	PlayerSAO *playersao = getplayersao(ref);
 	if (playersao == NULL)
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index dfc1b49d20b913262cf8da00f5160a318c3c8076..09f10e417e9ec40cfae02c7de57e6b0aadb76ea0 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -47,7 +47,7 @@ class ObjectRef : public ModApiBase {
 
 	static PlayerSAO* getplayersao(ObjectRef *ref);
 
-	static RemotePlayer* getplayer(ObjectRef *ref);
+	static RemotePlayer *getplayer(ObjectRef *ref);
 
 	// Exported functions
 
diff --git a/src/server.cpp b/src/server.cpp
index 71e71f43e5ad3b47f141e76bd5cc5f9c2d4e0864..a93c143c7d01f5d10e6fcbd23caa407394798f16 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -2688,7 +2688,7 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
 		SendChatMessage(PEER_ID_INEXISTENT,message);
 }
 
-void Server::UpdateCrafting(RemotePlayer* player)
+void Server::UpdateCrafting(RemotePlayer *player)
 {
 	DSTACK(FUNCTION_NAME);
 
@@ -3141,7 +3141,7 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
 
 	u16 peer_id = PEER_ID_INEXISTENT;
 	if (playername != "") {
-		RemotePlayer* player = m_env->getPlayer(playername.c_str());
+		RemotePlayer *player = m_env->getPlayer(playername.c_str());
 		if (!player)
 			return;
 		peer_id = player->peer_id;
@@ -3165,7 +3165,7 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
 
 	u16 peer_id = PEER_ID_INEXISTENT;
 	if (playername != "") {
-		RemotePlayer* player = m_env->getPlayer(playername.c_str());
+		RemotePlayer *player = m_env->getPlayer(playername.c_str());
 		if (!player)
 			return -1;
 		peer_id = player->peer_id;
@@ -3188,7 +3188,7 @@ void Server::deleteParticleSpawner(const std::string &playername, u32 id)
 
 	u16 peer_id = PEER_ID_INEXISTENT;
 	if (playername != "") {
-		RemotePlayer* player = m_env->getPlayer(playername.c_str());
+		RemotePlayer *player = m_env->getPlayer(playername.c_str());
 		if (!player)
 			return;
 		peer_id = player->peer_id;
diff --git a/src/server.h b/src/server.h
index fc4758c5f763093f51f22458f80b813408921427..6ee61a0eb6e9dab829751beac578f01b1ae631e2 100644
--- a/src/server.h
+++ b/src/server.h
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "environment.h"
 #include "chat_interface.h"
 #include "clientiface.h"
-#include "player.h"
+#include "remoteplayer.h"
 #include "network/networkpacket.h"
 #include <string>
 #include <list>