diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 17eabcb91538cdef91bcdacc4005ebd849ad599a..1f7ad2200886d0448ad1df4f4cd35a1cb02b131b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -50,6 +50,7 @@ configure_file(
 )
 
 set(common_SRCS
+	collision.cpp
 	nodemetadata.cpp
 	serverobject.cpp
 	noise.cpp
diff --git a/src/activeobject.h b/src/activeobject.h
index 041be0778b8f6d42abeee1d024aeeb9699bf7f26..e1fc6beaf1ee3d71d8e76e6486b56f63d1f8b7a3 100644
--- a/src/activeobject.h
+++ b/src/activeobject.h
@@ -39,6 +39,7 @@ struct ActiveObjectMessage
 #define ACTIVEOBJECT_TYPE_INVALID 0
 #define ACTIVEOBJECT_TYPE_TEST 1
 #define ACTIVEOBJECT_TYPE_ITEM 2
+#define ACTIVEOBJECT_TYPE_RAT 3
 
 /*
 	Parent class for ServerActiveObject and ClientActiveObject
diff --git a/src/clientobject.cpp b/src/clientobject.cpp
index a6aa033efcd533993ff0c1d3f01ac8d23f3d36c5..901b3d072cce3039b64cc5cf736c1999213b3150 100644
--- a/src/clientobject.cpp
+++ b/src/clientobject.cpp
@@ -258,6 +258,27 @@ void ItemCAO::removeFromScene()
 
 void ItemCAO::updateLight(u8 light_at_pos)
 {
+	if(m_node == NULL)
+		return;
+
+	u8 li = decode_light(light_at_pos);
+	video::SColor color(255,li,li,li);
+
+	scene::IMesh *mesh = m_node->getMesh();
+	if(mesh == NULL)
+		return;
+	
+	u16 mc = mesh->getMeshBufferCount();
+	for(u16 j=0; j<mc; j++)
+	{
+		scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+		video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+		u16 vc = buf->getVertexCount();
+		for(u16 i=0; i<vc; i++)
+		{
+			vertices[i].Color = color;
+		}
+	}
 }
 
 v3s16 ItemCAO::getLightPosition()
@@ -290,35 +311,54 @@ void ItemCAO::step(float dtime, ClientEnvironment *env)
 
 void ItemCAO::processMessage(const std::string &data)
 {
-	dstream<<"ItemCAO: Got data: "<<data<<std::endl;
+	dstream<<"ItemCAO: Got message"<<std::endl;
 	std::istringstream is(data, std::ios::binary);
-	u16 cmd;
-	is>>cmd;
+	char buf[4];
+	// command
+	is.read(buf, 1);
+	u8 cmd = buf[0];
 	if(cmd == 0)
 	{
-		v3f newpos;
-		is>>newpos.X;
-		is>>newpos.Y;
-		is>>newpos.Z;
-		m_position = newpos;
+		// pos
+		is.read(buf, 4);
+		m_position.X = (float)readS32((u8*)buf)/1000.0;
+		is.read(buf, 4);
+		m_position.Y = (float)readS32((u8*)buf)/1000.0;
+		is.read(buf, 4);
+		m_position.Z = (float)readS32((u8*)buf)/1000.0;
 		updateNodePos();
 	}
 }
 
 void ItemCAO::initialize(const std::string &data)
 {
-	dstream<<"ItemCAO: Got init data: "<<data<<std::endl;
+	dstream<<"ItemCAO: Got init data"<<std::endl;
+	
+	{
+		std::istringstream is(data, std::ios::binary);
+		char buf[4];
+		// version
+		is.read(buf, 1);
+		u8 version = buf[0];
+		// check version
+		if(version != 0)
+			return;
+		// pos
+		is.read(buf, 4);
+		m_position.X = (float)readS32((u8*)buf)/1000.0;
+		is.read(buf, 4);
+		m_position.Y = (float)readS32((u8*)buf)/1000.0;
+		is.read(buf, 4);
+		m_position.Z = (float)readS32((u8*)buf)/1000.0;
+		// inventorystring
+		m_inventorystring = deSerializeString(is);
+	}
 	
-	Strfnd fn(data);
-
-	v3f newpos;
-	newpos.X = stoi(fn.next(","));
-	newpos.Y = stoi(fn.next(","));
-	newpos.Z = stoi(fn.next(":"));
-	m_position = newpos;
 	updateNodePos();
 
-	m_inventorystring = fn.next("");
+	/*
+		Update image of node
+	*/
 
 	if(m_node == NULL)
 		return;
@@ -333,9 +373,7 @@ void ItemCAO::initialize(const std::string &data)
 	if(buf == NULL)
 		return;
 
-	/*
-		Create an inventory item to see what is its image
-	*/
+	// Create an inventory item to see what is its image
 	std::istringstream is(m_inventorystring, std::ios_base::binary);
 	video::ITexture *texture = NULL;
 	try{
diff --git a/src/main.cpp b/src/main.cpp
index 7749266d9f1b4d40a3f4d02acaa3cd2f98607cf2..92c012a909d72fccdec9df8d2f2837be96cfe462 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -72,10 +72,6 @@ SUGG: Split MapBlockObject serialization to to-client and to-disk
 	    them to clients
 	  - Not applicable. MapBlockObjects will be removed in the future.
 
-SUGG: MovingObject::move and Player::move are basically the same.
-      combine them.
-	  - NOTE: Player::move is more up-to-date.
-
 SUGG: Precalculate lighting translation table at runtime (at startup)
       - This is not doable because it is currently hand-made and not
 	    based on some mathematical function.
@@ -204,6 +200,10 @@ FIXME: If something is removed from craftresult with a right click,
 
 TODO: Get rid of MapBlockObjects and use ActiveObjects
 
+SUGG: MovingObject::move and Player::move are basically the same.
+      combine them.
+	  - NOTE: Player::move is more up-to-date.
+
 Map:
 ----
 
@@ -2602,7 +2602,8 @@ int main(int argc, char *argv[])
 			
 			core::aabbox3d<f32> *selection_box
 					= selected_active_object->getSelectionBox();
-			// Box should exist because it was returned in the first place
+			// Box should exist because object was returned in the
+			// first place
 			assert(selection_box);
 
 			v3f pos = selected_active_object->getPosition();
@@ -2614,8 +2615,8 @@ int main(int argc, char *argv[])
 
 			hilightboxes.push_back(box_on_map);
 
-			infotext = narrow_to_wide("A ClientActiveObject");
-			//infotext = narrow_to_wide(selected_object->infoText());
+			//infotext = narrow_to_wide("A ClientActiveObject");
+			infotext = narrow_to_wide(selected_active_object->infoText());
 
 			if(g_input->getLeftClicked())
 			{
diff --git a/src/mapblockobject.cpp b/src/mapblockobject.cpp
index cd1618c3a60410960cc7aa99e82011465f720297..f59a90a5f930dbe8dae894c847503a485872b91e 100644
--- a/src/mapblockobject.cpp
+++ b/src/mapblockobject.cpp
@@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+// This file contains the DEPRECATED MapBlockObject system
+
 #include "mapblockobject.h"
 #include "mapblock.h"
 // For object wrapping
diff --git a/src/mapblockobject.h b/src/mapblockobject.h
index d157162ec0b4c0b778f22912aef60036272e268f..6a0c36d9cbf765084949f4bb1f8bdfec1cdf4fc2 100644
--- a/src/mapblockobject.h
+++ b/src/mapblockobject.h
@@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+// This file contains the DEPRECATED MapBlockObject system
+
 #ifndef MAPBLOCKOBJECT_HEADER
 #define MAPBLOCKOBJECT_HEADER
 
diff --git a/src/server.cpp b/src/server.cpp
index ab4032743121a8abcf34447303a4ae9db475227a..4334d77c71cb6612eb02e8b8633c4f0631ea79d2 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -2436,12 +2436,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 					return;
 				}
 
-				v3f pos = intToFloat(p_over, BS);
-				pos.Y -= BS*0.45;
-
 				dout_server<<"Placing a miscellaneous item on map"
 						<<std::endl;
-						
+				
+				// Calculate a position for it
+				v3f pos = intToFloat(p_over, BS);
+				//pos.Y -= BS*0.45;
+				pos.Y -= BS*0.25; // let it drop a bit
+				// Randomize a bit
+				pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
+				pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
+
 				/*
 					Create an ItemSAO
 				*/
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index f0ef7d8d60225135ca31514305926e6fe3695377..92a0b83f4b10bdfc6c729a4ff7c04b1670e94ab8 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <fstream>
 #include "environment.h"
 #include "inventory.h"
+#include "collision.h"
 
 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
 
@@ -135,7 +136,8 @@ ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
 ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
 		const std::string inventorystring):
 	ServerActiveObject(env, id, pos),
-	m_inventorystring(inventorystring)
+	m_inventorystring(inventorystring),
+	m_speed_f(0,0,0)
 {
 	dstream<<"Server: ItemSAO created with inventorystring=\""
 			<<m_inventorystring<<"\""<<std::endl;
@@ -147,7 +149,12 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
 {
 	std::istringstream is(data, std::ios::binary);
 	char buf[1];
-	is.read(buf, 1); // read version
+	// read version
+	is.read(buf, 1);
+	u8 version = buf[0];
+	// check if version is supported
+	if(version != 0)
+		return NULL;
 	std::string inventorystring = deSerializeString(is);
 	dstream<<"ItemSAO::create(): Creating item \""
 			<<inventorystring<<"\""<<std::endl;
@@ -156,20 +163,59 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
 
 void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
 {
+	core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
+	collisionMoveResult moveresult;
+	// Apply gravity
+	m_speed_f += v3f(0, -dtime*9.81*BS, 0);
+	// Maximum movement without glitches
+	f32 pos_max_d = BS*0.25;
+	// Limit speed
+	if(m_speed_f.getLength()*dtime > pos_max_d)
+		m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
+	v3f pos_f = getBasePosition();
+	v3f pos_f_old = pos_f;
+	moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
+			box, dtime, pos_f, m_speed_f);
+	
+	if(pos_f.getDistanceFrom(pos_f_old) > 0.01*BS)
+	{
+		setBasePosition(pos_f);
+
+		std::ostringstream os(std::ios::binary);
+		char buf[6];
+		// command (0 = update position)
+		buf[0] = 0;
+		os.write(buf, 1);
+		// pos
+		writeS32((u8*)buf, m_base_position.X*1000);
+		os.write(buf, 4);
+		writeS32((u8*)buf, m_base_position.Y*1000);
+		os.write(buf, 4);
+		writeS32((u8*)buf, m_base_position.Z*1000);
+		os.write(buf, 4);
+		// create message and add to list
+		ActiveObjectMessage aom(getId(), false, os.str());
+		messages.push_back(aom);
+	}
 }
 
 std::string ItemSAO::getClientInitializationData()
 {
-	dstream<<__FUNCTION_NAME<<std::endl;
-	std::string data;
-	data += itos(m_base_position.X);
-	data += ",";
-	data += itos(m_base_position.Y);
-	data += ",";
-	data += itos(m_base_position.Z);
-	data += ":";
-	data += m_inventorystring;
-	return data;
+	std::ostringstream os(std::ios::binary);
+	char buf[6];
+	// version
+	buf[0] = 0;
+	os.write(buf, 1);
+	// pos
+	writeS32((u8*)buf, m_base_position.X*1000);
+	os.write(buf, 4);
+	writeS32((u8*)buf, m_base_position.Y*1000);
+	os.write(buf, 4);
+	writeS32((u8*)buf, m_base_position.Z*1000);
+	os.write(buf, 4);
+	// inventorystring
+	os<<serializeString(m_inventorystring);
+	return os.str();
 }
 
 std::string ItemSAO::getStaticData()
@@ -177,8 +223,10 @@ std::string ItemSAO::getStaticData()
 	dstream<<__FUNCTION_NAME<<std::endl;
 	std::ostringstream os(std::ios::binary);
 	char buf[1];
-	buf[0] = 0; //version
+	// version
+	buf[0] = 0;
 	os.write(buf, 1);
+	// inventorystring
 	os<<serializeString(m_inventorystring);
 	return os.str();
 }
diff --git a/src/serverobject.h b/src/serverobject.h
index a307c421fb0a61c7bd9ccd2203f5143a8c4044ae..5e3afb57b0d08976baa8ba3954e638c45281904d 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -32,9 +32,11 @@ Some planning
 * Server environment adds an active object, which gets the id 1
 * The active object list is scanned for each client once in a while,
   and it finds out what objects have been added that are not known
-  by the client yet. This scan is initiated by the server and the
-  result ends up directly to the server.
+  by the client yet. This scan is initiated by the Server class and
+  the result ends up directly to the server.
 * A network packet is created with the info and sent to the client.
+* Environment converts objects to static data and static data to
+  objects, based on how close players are to them.
 
 */
 
@@ -148,6 +150,7 @@ class ItemSAO : public ServerActiveObject
 	InventoryItem* createInventoryItem();
 private:
 	std::string m_inventorystring;
+	v3f m_speed_f;
 };
 
 #endif