Browse Source

Some work-in-progress in hp and mobs and a frightening amount of random fixes.

Perttu Ahola 13 years ago
parent
commit
c638442e78

BIN
data/heart.png


BIN
data/oerkki1.png


BIN
data/stick.png


BIN
data/tool_mesepick.png


BIN
data/tool_steelaxe.png


BIN
data/tool_steelpick.png


BIN
data/tool_steelshovel.png


BIN
data/tool_stoneaxe.png


BIN
data/tool_stonepick.png


BIN
data/tool_stoneshovel.png


BIN
data/tool_woodaxe.png


BIN
data/tool_woodpick.png


BIN
data/tool_woodshovel.png


+ 2 - 0
minetest.conf.example

@@ -52,6 +52,8 @@
 # Set to true to enable creative mode (unlimited inventory)
 #creative_mode = false
 
+#enable_damage = false
+
 # Player and object positions are sent at intervals specified by this
 #objectdata_inverval = 0.2
 

+ 1 - 0
src/activeobject.h

@@ -40,6 +40,7 @@ struct ActiveObjectMessage
 #define ACTIVEOBJECT_TYPE_TEST 1
 #define ACTIVEOBJECT_TYPE_ITEM 2
 #define ACTIVEOBJECT_TYPE_RAT 3
+#define ACTIVEOBJECT_TYPE_OERKKI1 4
 
 /*
 	Parent class for ServerActiveObject and ClientActiveObject

+ 116 - 224
src/client.cpp

@@ -90,6 +90,7 @@ Client::Client(
 	m_connection_reinit_timer = 0.0;
 	m_avg_rtt_timer = 0.0;
 	m_playerpos_send_timer = 0.0;
+	m_ignore_damage_timer = 0.0;
 
 	//m_env_mutex.Init();
 	//m_con_mutex.Init();
@@ -154,6 +155,10 @@ void Client::step(float dtime)
 	if(dtime > 2.0)
 		dtime = 2.0;
 	
+	if(m_ignore_damage_timer > dtime)
+		m_ignore_damage_timer -= dtime;
+	else
+		m_ignore_damage_timer = 0.0;
 	
 	//dstream<<"Client steps "<<dtime<<std::endl;
 
@@ -311,6 +316,9 @@ void Client::step(float dtime)
 		Do stuff if connected
 	*/
 	
+	/*
+		Handle environment
+	*/
 	{
 		// 0ms
 		//JMutexAutoLock lock(m_env_mutex); //bulk comment-out
@@ -341,8 +349,37 @@ void Client::step(float dtime)
 			{
 			}
 		}
-	}
 
+		/*
+			Get events
+		*/
+		for(;;)
+		{
+			ClientEnvEvent event = m_env.getClientEvent();
+			if(event.type == CEE_NONE)
+			{
+				break;
+			}
+			else if(event.type == CEE_PLAYER_DAMAGE)
+			{
+				if(m_ignore_damage_timer <= 0)
+				{
+					u8 damage = event.player_damage.amount;
+					sendDamage(damage);
+
+					// Add to ClientEvent queue
+					ClientEvent event;
+					event.type = CE_PLAYER_DAMAGE;
+					event.player_damage.amount = damage;
+					m_client_event_queue.push_back(event);
+				}
+			}
+		}
+	}
+	
+	/*
+		Print some info
+	*/
 	{
 		float &counter = m_avg_rtt_timer;
 		counter += dtime;
@@ -355,6 +392,10 @@ void Client::step(float dtime)
 			dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
 		}
 	}
+
+	/*
+		Send player position to server
+	*/
 	{
 		float &counter = m_playerpos_send_timer;
 		counter += dtime;
@@ -388,6 +429,8 @@ void Client::step(float dtime)
 			}
 			if(r.ack_block_to_server)
 			{
+				/*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
+						<<","<<r.p.Z<<")"<<std::endl;*/
 				/*
 					Acknowledge block
 				*/
@@ -447,7 +490,7 @@ void Client::ReceiveAll()
 void Client::Receive()
 {
 	DSTACK(__FUNCTION_NAME);
-	u32 data_maxsize = 10000;
+	u32 data_maxsize = 200000;
 	Buffer<u8> data(data_maxsize);
 	u16 sender_peer_id;
 	u32 datasize;
@@ -1294,219 +1337,56 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 			}
 		}
 	}
-	else
-	{
-		dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
-				<<command<<std::endl;
-	}
-#if 0
-	// Default to queueing it (for slow commands)
-	else
+	else if(command == TOCLIENT_HP)
 	{
-		JMutexAutoLock lock(m_incoming_queue_mutex);
-		
-		IncomingPacket packet(data, datasize);
-		m_incoming_queue.push_back(packet);
-	}
-#endif
-}
-
-#if 0
-/*
-	Returns true if there was something in queue
-*/
-bool Client::AsyncProcessPacket()
-{
-	DSTACK(__FUNCTION_NAME);
-	
-	try //for catching con::PeerNotFoundException
-	{
-
-	con::Peer *peer;
-	{
-		//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
-		// All data is coming from the server
-		peer = m_con.GetPeer(PEER_ID_SERVER);
-	}
-	
-	u8 ser_version = m_server_ser_ver;
-
-	IncomingPacket packet = getPacket();
-	u8 *data = packet.m_data;
-	u32 datasize = packet.m_datalen;
-	
-	// An empty packet means queue is empty
-	if(data == NULL){
-		return false;
+		std::string datastring((char*)&data[2], datasize-2);
+		std::istringstream is(datastring, std::ios_base::binary);
+		Player *player = m_env.getLocalPlayer();
+		assert(player != NULL);
+		u8 hp = readU8(is);
+		player->hp = hp;
 	}
-	
-	if(datasize < 2)
-		return true;
-	
-	ToClientCommand command = (ToClientCommand)readU16(&data[0]);
-
-	if(command == TOCLIENT_BLOCKDATA)
+	else if(command == TOCLIENT_MOVE_PLAYER)
 	{
-		// Ignore too small packet
-		if(datasize < 8)
-			return true;
-			
-		v3s16 p;
-		p.X = readS16(&data[2]);
-		p.Y = readS16(&data[4]);
-		p.Z = readS16(&data[6]);
-		
-		/*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
-				<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-		/*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
-				<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-		
-		std::string datastring((char*)&data[8], datasize-8);
-		std::istringstream istr(datastring, std::ios_base::binary);
-		
-		MapSector *sector;
-		MapBlock *block;
-		
-		{ //envlock
-			//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
-			
-			v2s16 p2d(p.X, p.Z);
-			sector = m_env.getMap().emergeSector(p2d);
-			
-			v2s16 sp = sector->getPos();
-			if(sp != p2d)
-			{
-				dstream<<"ERROR: Got sector with getPos()="
-						<<"("<<sp.X<<","<<sp.Y<<"), tried to get"
-						<<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
-			}
-
-			assert(sp == p2d);
-			//assert(sector->getPos() == p2d);
-
-			//TimeTaker timer("MapBlock deSerialize");
-			// 0ms
-			
-			try{
-				block = sector->getBlockNoCreate(p.Y);
-				/*
-					Update an existing block
-				*/
-				//dstream<<"Updating"<<std::endl;
-				block->deSerialize(istr, ser_version);
-				//block->setChangedFlag();
-			}
-			catch(InvalidPositionException &e)
-			{
-				/*
-					Create a new block
-				*/
-				//dstream<<"Creating new"<<std::endl;
-				block = new MapBlock(&m_env.getMap(), p);
-				block->deSerialize(istr, ser_version);
-				sector->insertBlock(block);
-				//block->setChangedFlag();
-
-				//DEBUG
-				/*NodeMod mod;
-				mod.type = NODEMOD_CHANGECONTENT;
-				mod.param = CONTENT_MESE;
-				block->setTempMod(v3s16(8,10,8), mod);
-				block->setTempMod(v3s16(8,9,8), mod);
-				block->setTempMod(v3s16(8,8,8), mod);
-				block->setTempMod(v3s16(8,7,8), mod);
-				block->setTempMod(v3s16(8,6,8), mod);*/
-#if 0
-				/*
-					Add some coulds
-					Well, this is a dumb way to do it, they should just
-					be drawn as separate objects. But the looks of them
-					can be tested this way.
-				*/
-				if(p.Y == 3)
-				{
-					NodeMod mod;
-					mod.type = NODEMOD_CHANGECONTENT;
-					mod.param = CONTENT_CLOUD;
-					v3s16 p2;
-					p2.Y = 8;
-					for(p2.X=3; p2.X<=13; p2.X++)
-					for(p2.Z=3; p2.Z<=13; p2.Z++)
-					{
-						block->setTempMod(p2, mod);
-					}
-				}
-#endif
-			}
-		} //envlock
-		
-		/*
-			Acknowledge block.
-		*/
-		/*
-			[0] u16 command
-			[2] u8 count
-			[3] v3s16 pos_0
-			[3+6] v3s16 pos_1
-			...
-		*/
-		u32 replysize = 2+1+6;
-		SharedBuffer<u8> reply(replysize);
-		writeU16(&reply[0], TOSERVER_GOTBLOCKS);
-		reply[2] = 1;
-		writeV3S16(&reply[3], p);
-		// Send as reliable
-		m_con.Send(PEER_ID_SERVER, 1, reply, true);
+		std::string datastring((char*)&data[2], datasize-2);
+		std::istringstream is(datastring, std::ios_base::binary);
+		Player *player = m_env.getLocalPlayer();
+		assert(player != NULL);
+		v3f pos = readV3F1000(is);
+		f32 pitch = readF1000(is);
+		f32 yaw = readF1000(is);
+		player->setPosition(pos);
+		/*player->setPitch(pitch);
+		player->setYaw(yaw);*/
+
+		dstream<<"Client got TOCLIENT_MOVE_PLAYER"
+				<<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
+				<<" pitch="<<pitch
+				<<" yaw="<<yaw
+				<<std::endl;
 
 		/*
-			Update Mesh of this block and blocks at x-, y- and z-.
-			Environment should not be locked as it interlocks with the
-			main thread, from which is will want to retrieve textures.
+			Add to ClientEvent queue.
+			This has to be sent to the main program because otherwise
+			it would just force the pitch and yaw values to whatever
+			the camera points to.
 		*/
-
-		//m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
-		
-		MeshMakeData data;
-		{
-			//TimeTaker timer("data fill");
-			// 0ms
-			data.fill(getDayNightRatio(), block);
-		}
-		{
-			TimeTaker timer("make mesh");
-			scene::SMesh *mesh_new = NULL;
-			mesh_new = makeMapBlockMesh(&data);
-			block->replaceMesh(mesh_new);
-		}
+		ClientEvent event;
+		event.type = CE_PLAYER_FORCE_MOVE;
+		event.player_force_move.pitch = pitch;
+		event.player_force_move.yaw = yaw;
+		m_client_event_queue.push_back(event);
+
+		// Ignore damage for a few seconds, so that the player doesn't
+		// get damage from falling on ground
+		m_ignore_damage_timer = 3.0;
 	}
 	else
 	{
 		dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
 				<<command<<std::endl;
 	}
-
-	return true;
-
-	} //try
-	catch(con::PeerNotFoundException &e)
-	{
-		/*dout_client<<DTIME<<"Client::AsyncProcessData(): Cancelling: The server"
-				" connection doesn't exist (a timeout or not yet connected?)"<<std::endl;*/
-		return false;
-	}
-}
-
-bool Client::AsyncProcessData()
-{
-	for(;;)
-	{
-		bool r = AsyncProcessPacket();
-		if(r == false)
-			break;
-	}
-	return false;
 }
-#endif
 
 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
 {
@@ -1514,28 +1394,6 @@ void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
 	m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
 }
 
-#if 0
-IncomingPacket Client::getPacket()
-{
-	JMutexAutoLock lock(m_incoming_queue_mutex);
-	
-	core::list<IncomingPacket>::Iterator i;
-	// Refer to first one
-	i = m_incoming_queue.begin();
-
-	// If queue is empty, return empty packet
-	if(i == m_incoming_queue.end()){
-		IncomingPacket packet;
-		return packet;
-	}
-	
-	// Pop out first packet and return it
-	IncomingPacket packet = *i;
-	m_incoming_queue.erase(i);
-	return packet;
-}
-#endif
-
 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
 		v3s16 nodepos_oversurface, u16 item)
 {
@@ -1739,6 +1597,21 @@ void Client::sendChatMessage(const std::wstring &message)
 	Send(0, data, true);
 }
 
+void Client::sendDamage(u8 damage)
+{
+	DSTACK(__FUNCTION_NAME);
+	std::ostringstream os(std::ios_base::binary);
+
+	writeU16(os, TOSERVER_DAMAGE);
+	writeU8(os, damage);
+
+	// Make data buffer
+	std::string s = os.str();
+	SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+	// Send as reliable
+	Send(0, data, true);
+}
+
 void Client::sendPlayerPos()
 {
 	//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
@@ -2061,6 +1934,13 @@ u32 Client::getDayNightRatio()
 	return m_env.getDayNightRatio();
 }
 
+u16 Client::getHP()
+{
+	Player *player = m_env.getLocalPlayer();
+	assert(player != NULL);
+	return player->hp;
+}
+
 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
 {
 	/*dstream<<"Client::addUpdateMeshTask(): "
@@ -2141,3 +2021,15 @@ void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
 	catch(InvalidPositionException &e){}
 }
 
+ClientEvent Client::getClientEvent()
+{
+	if(m_client_event_queue.size() == 0)
+	{
+		ClientEvent event;
+		event.type = CE_NONE;
+		return event;
+	}
+	return m_client_event_queue.pop_front();
+}
+
+

+ 29 - 50
src/client.h

@@ -174,55 +174,28 @@ public:
 	MutexedQueue<MeshUpdateResult> m_queue_out;
 };
 
-#if 0
-struct IncomingPacket
+enum ClientEventType
 {
-	IncomingPacket()
-	{
-		m_data = NULL;
-		m_datalen = 0;
-		m_refcount = NULL;
-	}
-	IncomingPacket(const IncomingPacket &a)
-	{
-		m_data = a.m_data;
-		m_datalen = a.m_datalen;
-		m_refcount = a.m_refcount;
-		if(m_refcount != NULL)
-			(*m_refcount)++;
-	}
-	IncomingPacket(u8 *data, u32 datalen)
-	{
-		m_data = new u8[datalen];
-		memcpy(m_data, data, datalen);
-		m_datalen = datalen;
-		m_refcount = new s32(1);
-	}
-	~IncomingPacket()
-	{
-		if(m_refcount != NULL){
-			assert(*m_refcount > 0);
-			(*m_refcount)--;
-			if(*m_refcount == 0){
-				if(m_data != NULL)
-					delete[] m_data;
-				delete m_refcount;
-			}
-		}
-	}
-	/*IncomingPacket & operator=(IncomingPacket a)
-	{
-		m_data = a.m_data;
-		m_datalen = a.m_datalen;
-		m_refcount = a.m_refcount;
-		(*m_refcount)++;
-		return *this;
-	}*/
-	u8 *m_data;
-	u32 m_datalen;
-	s32 *m_refcount;
+	CE_NONE,
+	CE_PLAYER_DAMAGE,
+	CE_PLAYER_FORCE_MOVE
+};
+
+struct ClientEvent
+{
+	ClientEventType type;
+	union{
+		struct{
+		} none;
+		struct{
+			u8 amount;
+		} player_damage;
+		struct{
+			f32 pitch;
+			f32 yaw;
+		} player_force_move;
+	};
 };
-#endif
 
 class Client : public con::PeerHandler, public InventoryManager
 {
@@ -281,6 +254,7 @@ public:
 	void sendSignNodeText(v3s16 p, std::string text);
 	void sendInventoryAction(InventoryAction *a);
 	void sendChatMessage(const std::wstring &message);
+	void sendDamage(u8 damage);
 	
 	// locks envlock
 	void removeNode(v3s16 p);
@@ -330,6 +304,8 @@ public:
 
 	u32 getDayNightRatio();
 
+	u16 getHP();
+
 	//void updateSomeExpiredMeshes();
 	
 	void setTempMod(v3s16 p, NodeMod mod)
@@ -394,13 +370,13 @@ public:
 
 	u64 getMapSeed(){ return m_map_seed; }
 
-	/*
-		These are not thread-safe
-	*/
 	void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false);
 	// Including blocks at appropriate edges
 	void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false);
 
+	// Get event from queue. CE_NONE is returned if queue is empty.
+	ClientEvent getClientEvent();
+	
 private:
 	
 	// Virtual methods from con::PeerHandler
@@ -419,6 +395,7 @@ private:
 	float m_connection_reinit_timer;
 	float m_avg_rtt_timer;
 	float m_playerpos_send_timer;
+	float m_ignore_damage_timer; // Used after server moves player
 
 	MeshUpdateThread m_mesh_update_thread;
 	
@@ -454,6 +431,8 @@ private:
 	u64 m_map_seed;
 	
 	InventoryContext m_inventory_context;
+
+	Queue<ClientEvent> m_client_event_queue;
 };
 
 #endif // !SERVER

+ 178 - 1
src/clientobject.cpp

@@ -494,7 +494,7 @@ void RatCAO::updateLight(u8 light_at_pos)
 
 v3s16 RatCAO::getLightPosition()
 {
-	return floatToInt(m_position, BS);
+	return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
 }
 
 void RatCAO::updateNodePos()
@@ -552,4 +552,181 @@ void RatCAO::initialize(const std::string &data)
 	updateNodePos();
 }
 
+/*
+	Oerkki1CAO
+*/
+
+#include "inventory.h"
+
+// Prototype
+Oerkki1CAO proto_Oerkki1CAO;
+
+Oerkki1CAO::Oerkki1CAO():
+	ClientActiveObject(0),
+	m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
+	m_node(NULL),
+	m_position(v3f(0,10*BS,0)),
+	m_yaw(0)
+{
+	ClientActiveObject::registerType(getType(), create);
+}
+
+Oerkki1CAO::~Oerkki1CAO()
+{
+}
+
+ClientActiveObject* Oerkki1CAO::create()
+{
+	return new Oerkki1CAO();
+}
+
+void Oerkki1CAO::addToScene(scene::ISceneManager *smgr)
+{
+	if(m_node != NULL)
+		return;
+	
+	video::IVideoDriver* driver = smgr->getVideoDriver();
+	
+	scene::SMesh *mesh = new scene::SMesh();
+	scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+	video::SColor c(255,255,255,255);
+	video::S3DVertex vertices[4] =
+	{
+		video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
+		video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
+		video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
+		video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
+	};
+	u16 indices[] = {0,1,2,2,3,0};
+	buf->append(vertices, 4, indices, 6);
+	// Set material
+	buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+	buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
+	//buf->getMaterial().setTexture(0, NULL);
+	buf->getMaterial().setTexture
+			(0, driver->getTexture(porting::getDataPath("oerkki1.png").c_str()));
+	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
+	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+	// Add to mesh
+	mesh->addMeshBuffer(buf);
+	buf->drop();
+	m_node = smgr->addMeshSceneNode(mesh, NULL);
+	mesh->drop();
+	// Set it to use the materials of the meshbuffers directly.
+	// This is needed for changing the texture in the future
+	m_node->setReadOnlyMaterials(true);
+	updateNodePos();
+}
+
+void Oerkki1CAO::removeFromScene()
+{
+	if(m_node == NULL)
+		return;
+
+	m_node->remove();
+	m_node = NULL;
+}
+
+void Oerkki1CAO::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 Oerkki1CAO::getLightPosition()
+{
+	return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
+}
+
+void Oerkki1CAO::updateNodePos()
+{
+	if(m_node == NULL)
+		return;
+
+	//m_node->setPosition(m_position);
+	m_node->setPosition(pos_translator.vect_show);
+
+	v3f rot = m_node->getRotation();
+	rot.Y = 180.0 - m_yaw + 90.0;
+	m_node->setRotation(rot);
+}
+
+void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
+{
+	pos_translator.translate(dtime);
+	updateNodePos();
+
+	LocalPlayer *player = env->getLocalPlayer();
+	assert(player);
+	
+	v3f playerpos = player->getPosition();
+	v2f playerpos_2d(playerpos.X,playerpos.Z);
+	v2f objectpos_2d(m_position.X,m_position.Z);
+
+	if(fabs(objectpos_2d.Y - playerpos_2d.Y) < 2.0*BS &&
+			objectpos_2d.getDistanceFrom(playerpos_2d) < 1.0*BS)
+	{
+		if(m_attack_interval.step(dtime, 0.5))
+		{
+			env->damageLocalPlayer(2);
+		}
+	}
+}
+
+void Oerkki1CAO::processMessage(const std::string &data)
+{
+	//dstream<<"Oerkki1CAO: Got message"<<std::endl;
+	std::istringstream is(data, std::ios::binary);
+	// command
+	u8 cmd = readU8(is);
+	if(cmd == 0)
+	{
+		// pos
+		m_position = readV3F1000(is);
+		pos_translator.update(m_position);
+		// yaw
+		m_yaw = readF1000(is);
+		updateNodePos();
+	}
+}
+
+void Oerkki1CAO::initialize(const std::string &data)
+{
+	//dstream<<"Oerkki1CAO: Got init data"<<std::endl;
+	
+	{
+		std::istringstream is(data, std::ios::binary);
+		// version
+		u8 version = readU8(is);
+		// check version
+		if(version != 0)
+			return;
+		// pos
+		m_position = readV3F1000(is);
+		pos_translator.init(m_position);
+	}
+	
+	updateNodePos();
+}
+
 

+ 45 - 0
src/clientobject.h

@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "common_irrlicht.h"
 #include "activeobject.h"
+#include "utility.h"
 
 /*
 
@@ -267,5 +268,49 @@ private:
 	SmoothTranslator pos_translator;
 };
 
+/*
+	Oerkki1CAO
+*/
+
+class Oerkki1CAO : public ClientActiveObject
+{
+public:
+	Oerkki1CAO();
+	virtual ~Oerkki1CAO();
+	
+	u8 getType() const
+	{
+		return ACTIVEOBJECT_TYPE_OERKKI1;
+	}
+	
+	static ClientActiveObject* create();
+
+	void addToScene(scene::ISceneManager *smgr);
+	void removeFromScene();
+	void updateLight(u8 light_at_pos);
+	v3s16 getLightPosition();
+	void updateNodePos();
+
+	void step(float dtime, ClientEnvironment *env);
+
+	void processMessage(const std::string &data);
+
+	void initialize(const std::string &data);
+	
+	core::aabbox3d<f32>* getSelectionBox()
+		{return &m_selection_box;}
+	v3f getPosition()
+		{return pos_translator.vect_show;}
+		//{return m_position;}
+
+private:
+	IntervalLimiter m_attack_interval;
+	core::aabbox3d<f32> m_selection_box;
+	scene::IMeshSceneNode *m_node;
+	v3f m_position;
+	float m_yaw;
+	SmoothTranslator pos_translator;
+};
+
 #endif
 

+ 33 - 12
src/clientserver.h

@@ -33,15 +33,18 @@ enum ToClientCommand
 
 		[0] u16 TOSERVER_INIT
 		[2] u8 deployed version
-		[3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
-		[4] u64 map seed (new as of 2011-02-27)
+		[3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd 
+		([4] u64 map seed (new as of 2011-02-27))
+
+		NOTE: The position in here is deprecated; position is
+		      explicitly sent afterwards
 	*/
 
 	TOCLIENT_BLOCKDATA = 0x20, //TODO: Multiple blocks
 	TOCLIENT_ADDNODE = 0x21,
 	TOCLIENT_REMOVENODE = 0x22,
 	
-	TOCLIENT_PLAYERPOS = 0x23,
+	TOCLIENT_PLAYERPOS = 0x23, // Obsolete
 	/*
 		[0] u16 command
 		// Followed by an arbitary number of these:
@@ -62,9 +65,9 @@ enum ToClientCommand
 		[N] char[20] name
 	*/
 	
-	TOCLIENT_OPT_BLOCK_NOT_FOUND = 0x25, // Not used
+	TOCLIENT_OPT_BLOCK_NOT_FOUND = 0x25, // Obsolete
 
-	TOCLIENT_SECTORMETA = 0x26, // Not used
+	TOCLIENT_SECTORMETA = 0x26, // Obsolete
 	/*
 		[0] u16 command
 		[2] u8 sector count
@@ -134,6 +137,19 @@ enum ToClientCommand
 		}
 	*/
 
+	TOCLIENT_HP = 0x33,
+	/*
+		u16 command
+		u8 hp
+	*/
+
+	TOCLIENT_MOVE_PLAYER = 0x34,
+	/*
+		u16 command
+		v3f1000 player position
+		f1000 player pitch
+		f1000 player yaw
+	*/
 };
 
 enum ToServerCommand
@@ -155,9 +171,9 @@ enum ToServerCommand
 		[0] u16 TOSERVER_INIT2
 	*/
 
-	TOSERVER_GETBLOCK=0x20, // Not used
-	TOSERVER_ADDNODE = 0x21, // Not used
-	TOSERVER_REMOVENODE = 0x22, // deprecated
+	TOSERVER_GETBLOCK=0x20, // Obsolete
+	TOSERVER_ADDNODE = 0x21, // Obsolete
+	TOSERVER_REMOVENODE = 0x22, // Obsolete
 
 	TOSERVER_PLAYERPOS = 0x23,
 	/*
@@ -186,7 +202,7 @@ enum ToServerCommand
 		...
 	*/
 
-	TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // deprecated
+	TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // Obsolete
 	/*
 		[0] u16 command
 		[2] v3s16 pos
@@ -218,9 +234,9 @@ enum ToServerCommand
 		3: digging completed
 	*/
 	
-	TOSERVER_RELEASE = 0x29, // Not used
+	TOSERVER_RELEASE = 0x29, // Obsolete
 
-	TOSERVER_SIGNTEXT = 0x30,
+	TOSERVER_SIGNTEXT = 0x30, // Old signs
 	/*
 		u16 command
 		v3s16 blockpos
@@ -257,7 +273,12 @@ enum ToServerCommand
 		[3] u16 id
 		[5] u16 item
 	*/
-
+	
+	TOSERVER_DAMAGE = 0x35,
+	/*
+		u16 command
+		u8 amount
+	*/
 };
 
 inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)

+ 1 - 0
src/collision.cpp

@@ -70,6 +70,7 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
 	
 	/*
 		Go through every node around the object
+		TODO: Calculate the range of nodes that need to be checked
 	*/
 	for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
 	for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)

+ 10 - 0
src/collision.h

@@ -38,6 +38,16 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
 		f32 dtime, v3f &pos_f, v3f &speed_f);
 //{return collisionMoveResult();}
 
+enum CollisionType
+{
+	COLLISION_FALL
+};
+
+struct CollisionInfo
+{
+	CollisionType t;
+	f32 speed;
+};
 
 #endif
 

+ 1 - 0
src/defaultsettings.cpp

@@ -55,6 +55,7 @@ void set_default_settings()
 
 	g_settings.setDefault("enable_experimental", "false");
 	g_settings.setDefault("creative_mode", "false");
+	g_settings.setDefault("enable_damage", "false"); //TODO: Set to true
 
 	g_settings.setDefault("objectdata_interval", "0.2");
 	g_settings.setDefault("active_object_range", "2");

+ 148 - 30
src/environment.cpp

@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "environment.h"
 #include "filesys.h"
 #include "porting.h"
+#include "collision.h"
 
 Environment::Environment()
 {
@@ -377,6 +378,55 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
 	}
 }
 
+#if 0
+void spawnRandomObjects(MapBlock *block)
+{
+	for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+	for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+	{
+		bool last_node_walkable = false;
+		for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+		{
+			v3s16 p(x0,y0,z0);
+			MapNode n = block->getNodeNoEx(p);
+			if(n.d == CONTENT_IGNORE)
+				continue;
+			if(content_features(n.d).liquid_type != LIQUID_NONE)
+				continue;
+			if(content_features(n.d).walkable)
+			{
+				last_node_walkable = true;
+				continue;
+			}
+			if(last_node_walkable)
+			{
+				// If block contains light information
+				if(content_features(n.d).param_type == CPT_LIGHT)
+				{
+					if(n.getLight(LIGHTBANK_DAY) <= 5)
+					{
+						if(myrand() % 1000 == 0)
+						{
+							v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
+							pos_f.Y -= BS*0.4;
+							ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
+							std::string data = obj->getStaticData();
+							StaticObject s_obj(obj->getType(),
+									obj->getBasePosition(), data);
+							// Add one
+							block->m_static_objects.insert(0, s_obj);
+							delete obj;
+							block->setChangedFlag();
+						}
+					}
+				}
+			}
+			last_node_walkable = false;
+		}
+	}
+}
+#endif
+
 void ServerEnvironment::step(float dtime)
 {
 	DSTACK(__FUNCTION_NAME);
@@ -429,26 +479,29 @@ void ServerEnvironment::step(float dtime)
 			}
 		}
 	}
-	
+
 	/*
 		Step active objects
 	*/
-
-	bool send_recommended = false;
-	m_send_recommended_timer += dtime;
-	if(m_send_recommended_timer > 0.15)
 	{
-		m_send_recommended_timer = 0;
-		send_recommended = true;
-	}
+		//TimeTaker timer("Step active objects");
 
-	for(core::map<u16, ServerActiveObject*>::Iterator
-			i = m_active_objects.getIterator();
-			i.atEnd()==false; i++)
-	{
-		ServerActiveObject* obj = i.getNode()->getValue();
-		// Step object, putting messages directly to the queue
-		obj->step(dtime, m_active_object_messages, send_recommended);
+		bool send_recommended = false;
+		m_send_recommended_timer += dtime;
+		if(m_send_recommended_timer > 0.15)
+		{
+			m_send_recommended_timer = 0;
+			send_recommended = true;
+		}
+
+		for(core::map<u16, ServerActiveObject*>::Iterator
+				i = m_active_objects.getIterator();
+				i.atEnd()==false; i++)
+		{
+			ServerActiveObject* obj = i.getNode()->getValue();
+			// Step object, putting messages directly to the queue
+			obj->step(dtime, m_active_object_messages, send_recommended);
+		}
 	}
 
 	if(m_object_management_interval.step(dtime, 0.5))
@@ -506,7 +559,7 @@ void ServerEnvironment::step(float dtime)
 		
 
 		const s16 to_active_max_blocks = 3;
-		const f32 to_static_max_f = (to_active_max_blocks+1)*MAP_BLOCKSIZE*BS;
+		const f32 to_static_max_f = (to_active_max_blocks+2)*MAP_BLOCKSIZE*BS;
 
 		/*
 			Convert stored objects from blocks near the players to active.
@@ -719,7 +772,8 @@ void ServerEnvironment::step(float dtime)
 
 		//TestSAO *obj = new TestSAO(this, 0, pos);
 		//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
-		ServerActiveObject *obj = new RatSAO(this, 0, pos);
+		//ServerActiveObject *obj = new RatSAO(this, 0, pos);
+		ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
 		addActiveObject(obj);
 	}
 #endif
@@ -976,14 +1030,18 @@ void ClientEnvironment::step(float dtime)
 		//TimeTaker timer("Client m_map->timerUpdate()", g_device);
 		m_map->timerUpdate(dtime);
 	}
-
+	
+	// Get local player
+	LocalPlayer *lplayer = getLocalPlayer();
+	assert(lplayer);
+	// collision info queue
+	core::list<CollisionInfo> player_collisions;
+	
 	/*
 		Get the speed the player is going
 	*/
 	f32 player_speed = 0.001; // just some small value
-	LocalPlayer *lplayer = getLocalPlayer();
-	if(lplayer)
-		player_speed = lplayer->getSpeed().getLength();
+	player_speed = lplayer->getSpeed().getLength();
 	
 	/*
 		Maximum position increment
@@ -1036,20 +1094,18 @@ void ClientEnvironment::step(float dtime)
 		*/
 		
 		{
-			Player *player = getLocalPlayer();
-
-			v3f playerpos = player->getPosition();
+			v3f lplayerpos = lplayer->getPosition();
 			
 			// Apply physics
 			if(free_move == false)
 			{
 				// Gravity
-				v3f speed = player->getSpeed();
-				if(player->swimming_up == false)
+				v3f speed = lplayer->getSpeed();
+				if(lplayer->swimming_up == false)
 					speed.Y -= 9.81 * BS * dtime_part * 2;
 
 				// Water resistance
-				if(player->in_water_stable || player->in_water)
+				if(lplayer->in_water_stable || lplayer->in_water)
 				{
 					f32 max_down = 2.0*BS;
 					if(speed.Y < -max_down) speed.Y = -max_down;
@@ -1061,19 +1117,47 @@ void ClientEnvironment::step(float dtime)
 					}
 				}
 
-				player->setSpeed(speed);
+				lplayer->setSpeed(speed);
 			}
 
 			/*
-				Move the player.
+				Move the lplayer.
 				This also does collision detection.
 			*/
-			player->move(dtime_part, *m_map, position_max_increment);
+			lplayer->move(dtime_part, *m_map, position_max_increment,
+					&player_collisions);
 		}
 	}
 	while(dtime_downcount > 0.001);
 		
 	//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
+
+	for(core::list<CollisionInfo>::Iterator
+			i = player_collisions.begin();
+			i != player_collisions.end(); i++)
+	{
+		CollisionInfo &info = *i;
+		if(info.t == COLLISION_FALL)
+		{
+			//f32 tolerance = BS*10; // 2 without damage
+			f32 tolerance = BS*12; // 3 without damage
+			f32 factor = 1;
+			if(info.speed > tolerance)
+			{
+				f32 damage_f = (info.speed - tolerance)/BS*factor;
+				u16 damage = (u16)(damage_f+0.5);
+				if(lplayer->hp > damage)
+					lplayer->hp -= damage;
+				else
+					lplayer->hp = 0;
+
+				ClientEnvEvent event;
+				event.type = CEE_PLAYER_DAMAGE;
+				event.player_damage.amount = damage;
+				m_client_event_queue.push_back(event);
+			}
+		}
+	}
 	
 	/*
 		Stuff that can be done in an arbitarily large dtime
@@ -1287,6 +1371,30 @@ void ClientEnvironment::processActiveObjectMessage(u16 id,
 	obj->processMessage(data);
 }
 
+/*
+	Callbacks for activeobjects
+*/
+
+void ClientEnvironment::damageLocalPlayer(u8 damage)
+{
+	LocalPlayer *lplayer = getLocalPlayer();
+	assert(lplayer);
+
+	if(lplayer->hp > damage)
+		lplayer->hp -= damage;
+	else
+		lplayer->hp = 0;
+
+	ClientEnvEvent event;
+	event.type = CEE_PLAYER_DAMAGE;
+	event.player_damage.amount = damage;
+	m_client_event_queue.push_back(event);
+}
+
+/*
+	Client likes to call these
+*/
+	
 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
 		core::array<DistanceSortedActiveObject> &dest)
 {
@@ -1307,6 +1415,16 @@ void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
 	}
 }
 
+ClientEnvEvent ClientEnvironment::getClientEvent()
+{
+	if(m_client_event_queue.size() == 0)
+	{
+		ClientEnvEvent event;
+		event.type = CEE_NONE;
+		return event;
+	}
+	return m_client_event_queue.pop_front();
+}
 
 #endif // #ifndef SERVER
 

+ 32 - 0
src/environment.h

@@ -170,6 +170,24 @@ private:
 	Client uses an environment mutex.
 */
 
+enum ClientEnvEventType
+{
+	CEE_NONE,
+	CEE_PLAYER_DAMAGE
+};
+
+struct ClientEnvEvent
+{
+	ClientEnvEventType type;
+	union {
+		struct{
+		} none;
+		struct{
+			u8 amount;
+		} player_damage;
+	};
+};
+
 class ClientEnvironment : public Environment
 {
 public:
@@ -214,15 +232,29 @@ public:
 	void removeActiveObject(u16 id);
 
 	void processActiveObjectMessage(u16 id, const std::string &data);
+
+	/*
+		Callbacks for activeobjects
+	*/
+
+	void damageLocalPlayer(u8 damage);
+
+	/*
+		Client likes to call these
+	*/
 	
 	// Get all nearby objects
 	void getActiveObjects(v3f origin, f32 max_d,
 			core::array<DistanceSortedActiveObject> &dest);
 	
+	// Get event from queue. CEE_NONE is returned if queue is empty.
+	ClientEnvEvent getClientEvent();
+	
 private:
 	ClientMap *m_map;
 	scene::ISceneManager *m_smgr;
 	core::map<u16, ClientActiveObject*> m_active_objects;
+	Queue<ClientEnvEvent> m_client_event_queue;
 };
 
 #endif

+ 6 - 0
src/inventory.h

@@ -369,6 +369,12 @@ public:
 			basename = "tool_stoneaxe.png";
 		else if(m_toolname == "SteelAxe")
 			basename = "tool_steelaxe.png";
+		else if(m_toolname == "WSword")
+			basename = "tool_woodsword.png";
+		else if(m_toolname == "STSword")
+			basename = "tool_stonesword.png";
+		else if(m_toolname == "SteelSword")
+			basename = "tool_steelsword.png";
 		else
 			basename = "cloud.png";
 		

+ 312 - 239
src/main.cpp

@@ -93,6 +93,10 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into
 SUGG: Calculate lighting per vertex to get a lighting effect like in
       bartwe's game
 
+SUGG: Background music based on cellular automata?
+      http://www.earslap.com/projectslab/otomata
+
+
 Gaming ideas:
 -------------
 
@@ -126,6 +130,12 @@ Game content:
 	- You can drop on top of it, and have some time to attack there
 	  before he shakes you off
 
+- Maybe the difficulty could come from monsters getting tougher in
+  far-away places, and the player starting to need something from
+  there when time goes by.
+  - The player would have some of that stuff at the beginning, and
+    would need new supplies of it when it runs out
+
 Documentation:
 --------------
 
@@ -1210,7 +1220,7 @@ void updateViewingRange(f32 frametime_in, Client *client)
 
 void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
 		v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
-		Inventory *inventory)
+		Inventory *inventory, s32 halfheartcount)
 {
 	InventoryList *mainlist = inventory->getList("main");
 	if(mainlist == NULL)
@@ -1259,6 +1269,40 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
 			drawInventoryItem(driver, font, item, rect, NULL);
 		}
 	}
+	
+	/*
+		Draw hearts
+	*/
+	{
+		video::ITexture *heart_texture =
+				driver->getTexture(porting::getDataPath("heart.png").c_str());
+		v2s32 p = pos + v2s32(0, -20);
+		for(s32 i=0; i<halfheartcount/2; i++)
+		{
+			const video::SColor color(255,255,255,255);
+			const video::SColor colors[] = {color,color,color,color};
+			core::rect<s32> rect(0,0,16,16);
+			rect += p;
+			driver->draw2DImage(heart_texture, rect,
+				core::rect<s32>(core::position2d<s32>(0,0),
+				core::dimension2di(heart_texture->getOriginalSize())),
+				NULL, colors, true);
+			p += v2s32(20,0);
+		}
+		if(halfheartcount % 2 == 1)
+		{
+			const video::SColor color(255,255,255,255);
+			const video::SColor colors[] = {color,color,color,color};
+			core::rect<s32> rect(0,0,16/2,16);
+			rect += p;
+			core::dimension2di srcd(heart_texture->getOriginalSize());
+			srcd.Width /= 2;
+			driver->draw2DImage(heart_texture, rect,
+				core::rect<s32>(core::position2d<s32>(0,0), srcd),
+				NULL, colors, true);
+			p += v2s32(20,0);
+		}
+	}
 }
 
 #if 0
@@ -1519,6 +1563,215 @@ void SpeedTests()
 	}
 }
 
+void getPointedNode(v3f player_position,
+		v3f camera_direction, v3f camera_position,
+		bool &nodefound, core::line3d<f32> shootline,
+		v3s16 &nodepos, v3s16 &neighbourpos,
+		core::aabbox3d<f32> &nodehilightbox,
+		f32 d)
+{
+	assert(g_client);
+
+	f32 mindistance = BS * 1001;
+	
+	v3s16 pos_i = floatToInt(player_position, BS);
+
+	/*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
+			<<std::endl;*/
+
+	s16 a = d;
+	s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
+	s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
+	s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
+	s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
+	s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
+	s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
+	
+	for(s16 y = ystart; y <= yend; y++)
+	for(s16 z = zstart; z <= zend; z++)
+	for(s16 x = xstart; x <= xend; x++)
+	{
+		MapNode n;
+		try
+		{
+			n = g_client->getNode(v3s16(x,y,z));
+			if(content_pointable(n.d) == false)
+				continue;
+		}
+		catch(InvalidPositionException &e)
+		{
+			continue;
+		}
+
+		v3s16 np(x,y,z);
+		v3f npf = intToFloat(np, BS);
+		
+		f32 d = 0.01;
+		
+		v3s16 dirs[6] = {
+			v3s16(0,0,1), // back
+			v3s16(0,1,0), // top
+			v3s16(1,0,0), // right
+			v3s16(0,0,-1), // front
+			v3s16(0,-1,0), // bottom
+			v3s16(-1,0,0), // left
+		};
+		
+		/*
+			Meta-objects
+		*/
+		if(n.d == CONTENT_TORCH)
+		{
+			v3s16 dir = unpackDir(n.dir);
+			v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
+			dir_f *= BS/2 - BS/6 - BS/20;
+			v3f cpf = npf + dir_f;
+			f32 distance = (cpf - camera_position).getLength();
+
+			core::aabbox3d<f32> box;
+			
+			// bottom
+			if(dir == v3s16(0,-1,0))
+			{
+				box = core::aabbox3d<f32>(
+					npf - v3f(BS/6, BS/2, BS/6),
+					npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
+				);
+			}
+			// top
+			else if(dir == v3s16(0,1,0))
+			{
+				box = core::aabbox3d<f32>(
+					npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
+					npf + v3f(BS/6, BS/2, BS/6)
+				);
+			}
+			// side
+			else
+			{
+				box = core::aabbox3d<f32>(
+					cpf - v3f(BS/6, BS/3, BS/6),
+					cpf + v3f(BS/6, BS/3, BS/6)
+				);
+			}
+
+			if(distance < mindistance)
+			{
+				if(box.intersectsWithLine(shootline))
+				{
+					nodefound = true;
+					nodepos = np;
+					neighbourpos = np;
+					mindistance = distance;
+					nodehilightbox = box;
+				}
+			}
+		}
+		else if(n.d == CONTENT_SIGN_WALL)
+		{
+			v3s16 dir = unpackDir(n.dir);
+			v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
+			dir_f *= BS/2 - BS/6 - BS/20;
+			v3f cpf = npf + dir_f;
+			f32 distance = (cpf - camera_position).getLength();
+
+			v3f vertices[4] =
+			{
+				v3f(BS*0.42,-BS*0.35,-BS*0.4),
+				v3f(BS*0.49, BS*0.35, BS*0.4),
+			};
+
+			for(s32 i=0; i<2; i++)
+			{
+				if(dir == v3s16(1,0,0))
+					vertices[i].rotateXZBy(0);
+				if(dir == v3s16(-1,0,0))
+					vertices[i].rotateXZBy(180);
+				if(dir == v3s16(0,0,1))
+					vertices[i].rotateXZBy(90);
+				if(dir == v3s16(0,0,-1))
+					vertices[i].rotateXZBy(-90);
+				if(dir == v3s16(0,-1,0))
+					vertices[i].rotateXYBy(-90);
+				if(dir == v3s16(0,1,0))
+					vertices[i].rotateXYBy(90);
+
+				vertices[i] += npf;
+			}
+
+			core::aabbox3d<f32> box;
+
+			box = core::aabbox3d<f32>(vertices[0]);
+			box.addInternalPoint(vertices[1]);
+
+			if(distance < mindistance)
+			{
+				if(box.intersectsWithLine(shootline))
+				{
+					nodefound = true;
+					nodepos = np;
+					neighbourpos = np;
+					mindistance = distance;
+					nodehilightbox = box;
+				}
+			}
+		}
+		/*
+			Regular blocks
+		*/
+		else
+		{
+			for(u16 i=0; i<6; i++)
+			{
+				v3f dir_f = v3f(dirs[i].X,
+						dirs[i].Y, dirs[i].Z);
+				v3f centerpoint = npf + dir_f * BS/2;
+				f32 distance =
+						(centerpoint - camera_position).getLength();
+				
+				if(distance < mindistance)
+				{
+					core::CMatrix4<f32> m;
+					m.buildRotateFromTo(v3f(0,0,1), dir_f);
+
+					// This is the back face
+					v3f corners[2] = {
+						v3f(BS/2, BS/2, BS/2),
+						v3f(-BS/2, -BS/2, BS/2+d)
+					};
+					
+					for(u16 j=0; j<2; j++)
+					{
+						m.rotateVect(corners[j]);
+						corners[j] += npf;
+					}
+
+					core::aabbox3d<f32> facebox(corners[0]);
+					facebox.addInternalPoint(corners[1]);
+
+					if(facebox.intersectsWithLine(shootline))
+					{
+						nodefound = true;
+						nodepos = np;
+						neighbourpos = np + dirs[i];
+						mindistance = distance;
+
+						//nodehilightbox = facebox;
+
+						const float d = 0.502;
+						core::aabbox3d<f32> nodebox
+								(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
+						v3f nodepos_f = intToFloat(nodepos, BS);
+						nodebox.MinEdge += nodepos_f;
+						nodebox.MaxEdge += nodepos_f;
+						nodehilightbox = nodebox;
+					}
+				} // if distance < mindistance
+			} // for dirs
+		} // regular block
+	} // for coords
+}
+
 int main(int argc, char *argv[])
 {
 	/*
@@ -2148,30 +2401,14 @@ int main(int argc, char *argv[])
 
 	//video::SColor skycolor = video::SColor(255,90,140,200);
 	//video::SColor skycolor = video::SColor(255,166,202,244);
-	video::SColor skycolor = video::SColor(255,120,185,244);
+	//video::SColor skycolor = video::SColor(255,120,185,244);
+	video::SColor skycolor = video::SColor(255,140,186,250);
 
 	camera->setFOV(FOV_ANGLE);
 
 	// Just so big a value that everything rendered is visible
 	camera->setFarValue(100000*BS);
 	
-	/*
-		Lighting test code. Doesn't quite work this way.
-		The CPU-computed lighting is good.
-	*/
-
-	/*
-	smgr->addLightSceneNode(NULL,
-		v3f(0, BS*1000000, 0),
-		video::SColorf(0.3,0.3,0.3),
-		BS*10000000);
-
-	smgr->setAmbientLight(video::SColorf(0.0, 0.0, 0.0));
-
-	scene::ILightSceneNode *light = smgr->addLightSceneNode(camera,
-			v3f(0, 0, 0), video::SColorf(0.5,0.5,0.5), BS*4);
-	*/
-
 	f32 camera_yaw = 0; // "right/left"
 	f32 camera_pitch = 0; // "up/down"
 
@@ -2226,6 +2463,8 @@ int main(int argc, char *argv[])
 
 	core::list<float> frametime_log;
 
+	float damage_flash_timer = 0;
+
 	/*
 		Main loop
 	*/
@@ -2453,6 +2692,16 @@ int main(int argc, char *argv[])
 			);
 			client.setPlayerControl(control);
 		}
+		
+		/*
+			Run server
+		*/
+
+		if(server != NULL)
+		{
+			//TimeTaker timer("server->step(dtime)");
+			server->step(dtime);
+		}
 
 		/*
 			Process environment
@@ -2464,12 +2713,28 @@ int main(int argc, char *argv[])
 			//client.step(dtime_avg1);
 		}
 
-		if(server != NULL)
+		// Read client events
+		for(;;)
 		{
-			//TimeTaker timer("server->step(dtime)");
-			server->step(dtime);
+			ClientEvent event = client.getClientEvent();
+			if(event.type == CE_NONE)
+			{
+				break;
+			}
+			else if(event.type == CE_PLAYER_DAMAGE)
+			{
+				//u16 damage = event.player_damage.amount;
+				//dstream<<"Player damage: "<<damage<<std::endl;
+				damage_flash_timer = 0.05;
+			}
+			else if(event.type == CE_PLAYER_FORCE_MOVE)
+			{
+				camera_yaw = event.player_force_move.yaw;
+				camera_pitch = event.player_force_move.pitch;
+			}
 		}
-
+		
+		// Get player position
 		v3f player_position = client.getPlayerPosition();
 		
 		//TimeTaker //timer2("//timer2");
@@ -2637,22 +2902,6 @@ int main(int argc, char *argv[])
 			else if(g_input->getRightClicked())
 			{
 				std::cout<<DTIME<<"Right-clicked object"<<std::endl;
-#if 0
-				/*
-					Check if we want to modify the object ourselves
-				*/
-				if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)
-				{
-				}
-				/*
-					Otherwise pass the event to the server as-is
-				*/
-				else
-				{
-					client.clickObject(1, selected_object->getBlock()->getPos(),
-							selected_object->getId(), g_selected_item);
-				}
-#endif
 			}
 		}
 		else // selected_object == NULL
@@ -2666,205 +2915,13 @@ int main(int argc, char *argv[])
 		v3s16 nodepos;
 		v3s16 neighbourpos;
 		core::aabbox3d<f32> nodehilightbox;
-		f32 mindistance = BS * 1001;
-		
-		v3s16 pos_i = floatToInt(player_position, BS);
-
-		/*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
-				<<std::endl;*/
-
-		s16 a = d;
-		s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
-		s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
-		s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
-		s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
-		s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
-		s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
-		
-		for(s16 y = ystart; y <= yend; y++)
-		for(s16 z = zstart; z <= zend; z++)
-		for(s16 x = xstart; x <= xend; x++)
-		{
-			MapNode n;
-			try
-			{
-				n = client.getNode(v3s16(x,y,z));
-				if(content_pointable(n.d) == false)
-					continue;
-			}
-			catch(InvalidPositionException &e)
-			{
-				continue;
-			}
-
-			v3s16 np(x,y,z);
-			v3f npf = intToFloat(np, BS);
-			
-			f32 d = 0.01;
-			
-			v3s16 dirs[6] = {
-				v3s16(0,0,1), // back
-				v3s16(0,1,0), // top
-				v3s16(1,0,0), // right
-				v3s16(0,0,-1), // front
-				v3s16(0,-1,0), // bottom
-				v3s16(-1,0,0), // left
-			};
-			
-			/*
-				Meta-objects
-			*/
-			if(n.d == CONTENT_TORCH)
-			{
-				v3s16 dir = unpackDir(n.dir);
-				v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
-				dir_f *= BS/2 - BS/6 - BS/20;
-				v3f cpf = npf + dir_f;
-				f32 distance = (cpf - camera_position).getLength();
-
-				core::aabbox3d<f32> box;
-				
-				// bottom
-				if(dir == v3s16(0,-1,0))
-				{
-					box = core::aabbox3d<f32>(
-						npf - v3f(BS/6, BS/2, BS/6),
-						npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
-					);
-				}
-				// top
-				else if(dir == v3s16(0,1,0))
-				{
-					box = core::aabbox3d<f32>(
-						npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
-						npf + v3f(BS/6, BS/2, BS/6)
-					);
-				}
-				// side
-				else
-				{
-					box = core::aabbox3d<f32>(
-						cpf - v3f(BS/6, BS/3, BS/6),
-						cpf + v3f(BS/6, BS/3, BS/6)
-					);
-				}
-
-				if(distance < mindistance)
-				{
-					if(box.intersectsWithLine(shootline))
-					{
-						nodefound = true;
-						nodepos = np;
-						neighbourpos = np;
-						mindistance = distance;
-						nodehilightbox = box;
-					}
-				}
-			}
-			else if(n.d == CONTENT_SIGN_WALL)
-			{
-				v3s16 dir = unpackDir(n.dir);
-				v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
-				dir_f *= BS/2 - BS/6 - BS/20;
-				v3f cpf = npf + dir_f;
-				f32 distance = (cpf - camera_position).getLength();
-
-				v3f vertices[4] =
-				{
-					v3f(BS*0.42,-BS*0.35,-BS*0.4),
-					v3f(BS*0.49, BS*0.35, BS*0.4),
-				};
-
-				for(s32 i=0; i<2; i++)
-				{
-					if(dir == v3s16(1,0,0))
-						vertices[i].rotateXZBy(0);
-					if(dir == v3s16(-1,0,0))
-						vertices[i].rotateXZBy(180);
-					if(dir == v3s16(0,0,1))
-						vertices[i].rotateXZBy(90);
-					if(dir == v3s16(0,0,-1))
-						vertices[i].rotateXZBy(-90);
-					if(dir == v3s16(0,-1,0))
-						vertices[i].rotateXYBy(-90);
-					if(dir == v3s16(0,1,0))
-						vertices[i].rotateXYBy(90);
-
-					vertices[i] += npf;
-				}
-
-				core::aabbox3d<f32> box;
-
-				box = core::aabbox3d<f32>(vertices[0]);
-				box.addInternalPoint(vertices[1]);
-
-				if(distance < mindistance)
-				{
-					if(box.intersectsWithLine(shootline))
-					{
-						nodefound = true;
-						nodepos = np;
-						neighbourpos = np;
-						mindistance = distance;
-						nodehilightbox = box;
-					}
-				}
-			}
-			/*
-				Regular blocks
-			*/
-			else
-			{
-				for(u16 i=0; i<6; i++)
-				{
-					v3f dir_f = v3f(dirs[i].X,
-							dirs[i].Y, dirs[i].Z);
-					v3f centerpoint = npf + dir_f * BS/2;
-					f32 distance =
-							(centerpoint - camera_position).getLength();
-					
-					if(distance < mindistance)
-					{
-						core::CMatrix4<f32> m;
-						m.buildRotateFromTo(v3f(0,0,1), dir_f);
-
-						// This is the back face
-						v3f corners[2] = {
-							v3f(BS/2, BS/2, BS/2),
-							v3f(-BS/2, -BS/2, BS/2+d)
-						};
-						
-						for(u16 j=0; j<2; j++)
-						{
-							m.rotateVect(corners[j]);
-							corners[j] += npf;
-						}
-
-						core::aabbox3d<f32> facebox(corners[0]);
-						facebox.addInternalPoint(corners[1]);
-
-						if(facebox.intersectsWithLine(shootline))
-						{
-							nodefound = true;
-							nodepos = np;
-							neighbourpos = np + dirs[i];
-							mindistance = distance;
-
-							//nodehilightbox = facebox;
-
-							const float d = 0.502;
-							core::aabbox3d<f32> nodebox
-									(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
-							v3f nodepos_f = intToFloat(nodepos, BS);
-							nodebox.MinEdge += nodepos_f;
-							nodebox.MaxEdge += nodepos_f;
-							nodehilightbox = nodebox;
-						}
-					} // if distance < mindistance
-				} // for dirs
-			} // regular block
-		} // for coords
 
+		getPointedNode(player_position,
+				camera_direction, camera_position,
+				nodefound, shootline,
+				nodepos, neighbourpos,
+				nodehilightbox, d);
+	
 		static float nodig_delay_counter = 0.0;
 
 		if(nodefound)
@@ -3430,10 +3487,26 @@ int main(int argc, char *argv[])
 		*/
 		{
 			draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),
-					hotbar_imagesize, hotbar_itemcount, &local_inventory);
+					hotbar_imagesize, hotbar_itemcount, &local_inventory,
+					client.getHP());
+		}
+
+		/*
+			Damage flash
+		*/
+		if(damage_flash_timer > 0.0)
+		{
+			damage_flash_timer -= dtime;
+			
+			video::SColor color(128,255,0,0);
+			driver->draw2DRectangle(color,
+					core::rect<s32>(0,0,screensize.X,screensize.Y),
+					NULL);
 		}
 		
-		// End drawing
+		/*
+			End scene
+		*/
 		{
 			TimeTaker timer("endScene");
 			driver->endScene();

+ 24 - 12
src/map.cpp

@@ -37,8 +37,8 @@ Map::Map(std::ostream &dout):
 	m_dout(dout),
 	m_sector_cache(NULL)
 {
-	m_sector_mutex.Init();
-	assert(m_sector_mutex.IsInitialized());
+	/*m_sector_mutex.Init();
+	assert(m_sector_mutex.IsInitialized());*/
 }
 
 Map::~Map()
@@ -104,7 +104,7 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
 
 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
 {
-	JMutexAutoLock lock(m_sector_mutex);
+	//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 
 	return getSectorNoGenerateNoExNoLock(p);
 }
@@ -1347,7 +1347,7 @@ bool Map::dayNightDiffed(v3s16 blockpos)
 */
 void Map::timerUpdate(float dtime)
 {
-	JMutexAutoLock lock(m_sector_mutex);
+	//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 
 	core::map<v2s16, MapSector*>::Iterator si;
 
@@ -1397,7 +1397,7 @@ void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
 u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
 		core::list<v3s16> *deleted_blocks)
 {
-	JMutexAutoLock lock(m_sector_mutex);
+	//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 
 	core::list<v2s16> sector_deletion_queue;
 	core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
@@ -2163,6 +2163,18 @@ void addRandomObjects(MapBlock *block)
 							block->m_static_objects.insert(0, s_obj);
 							delete obj;
 						}
+						if(myrand() % 300 == 0)
+						{
+							v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
+							pos_f.Y -= BS*0.4;
+							ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
+							std::string data = obj->getStaticData();
+							StaticObject s_obj(obj->getType(),
+									obj->getBasePosition(), data);
+							// Add one
+							block->m_static_objects.insert(0, s_obj);
+							delete obj;
+						}
 					}
 				}
 			}
@@ -4714,7 +4726,7 @@ plan_b:
 	// This won't work if proper generation is disabled
 	if(m_chunksize == 0)
 		return WATER_LEVEL+2;
-	double level = base_rock_level_2d(m_seed, p2d);
+	double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
 	return (s16)level;
 }
 
@@ -4794,7 +4806,7 @@ void ServerMap::save(bool only_changed)
 	u32 block_count = 0;
 	
 	{ //sectorlock
-	JMutexAutoLock lock(m_sector_mutex);
+	//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 	
 	core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
 	for(; i.atEnd() == false; i++)
@@ -4856,7 +4868,7 @@ void ServerMap::loadAll()
 
 	dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
 	
-	JMutexAutoLock lock(m_sector_mutex);
+	//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 	
 	s32 counter = 0;
 	s32 printed_counter = -100000;
@@ -5163,7 +5175,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
 
 	MapSector *sector = NULL;
 
-	JMutexAutoLock lock(m_sector_mutex);
+	//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 
 	try{
 		sector = loadSectorMeta(sectorsubdir);
@@ -5410,7 +5422,7 @@ MapSector * ClientMap::emergeSector(v2s16 p2d)
 	ClientMapSector *sector = new ClientMapSector(this, p2d);
 	
 	{
-		JMutexAutoLock lock(m_sector_mutex);
+		//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 		m_sectors.insert(p2d, sector);
 	}
 	
@@ -5422,7 +5434,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
 	DSTACK(__FUNCTION_NAME);
 	ClientMapSector *sector = NULL;
 
-	JMutexAutoLock lock(m_sector_mutex);
+	//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 	
 	core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
 
@@ -5435,7 +5447,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
 	{
 		sector = new ClientMapSector(this, p2d);
 		{
-			JMutexAutoLock lock(m_sector_mutex);
+			//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
 			m_sectors.insert(p2d, sector);
 		}
 	}

+ 6 - 4
src/map.h

@@ -287,6 +287,11 @@ public:
 	void removeNodeMetadata(v3s16 p);
 	void nodeMetadataStep(float dtime,
 			core::map<v3s16, MapBlock*> &changed_blocks);
+	
+	/*
+		Misc.
+	*/
+	core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
 
 	/*
 		Variables
@@ -298,16 +303,13 @@ protected:
 
 	core::map<MapEventReceiver*, bool> m_event_receivers;
 	
-	// Mutex is important because on client map is accessed asynchronously
 	core::map<v2s16, MapSector*> m_sectors;
-	JMutex m_sector_mutex;
+	//JMutex m_sector_mutex;
 
 	// Be sure to set this to NULL when the cached sector is deleted 
 	MapSector *m_sector_cache;
 	v2s16 m_sector_cache_p;
 
-	//WrapperHeightmap m_hwrapper;
-	
 	// Queued transforming water nodes
 	UniqueQueue<v3s16> m_transforming_liquid;
 };

+ 27 - 6
src/mapblock.cpp

@@ -1924,9 +1924,19 @@ void MapBlock::serialize(std::ostream &os, u8 version)
 		*/
 		if(version >= 14)
 		{
-			std::ostringstream oss(std::ios_base::binary);
-			m_node_metadata.serialize(oss);
-			os<<serializeString(oss.str());
+			if(version <= 15)
+			{
+				std::ostringstream oss(std::ios_base::binary);
+				m_node_metadata.serialize(oss);
+				os<<serializeString(oss.str());
+			}
+			else
+			{
+				std::ostringstream oss(std::ios_base::binary);
+				m_node_metadata.serialize(oss);
+				compressZlib(oss.str(), os);
+				//os<<serializeLongString(oss.str());
+			}
 		}
 	}
 }
@@ -2055,9 +2065,20 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
 		{
 			// Ignore errors
 			try{
-				std::string data = deSerializeString(is);
-				std::istringstream iss(data, std::ios_base::binary);
-				m_node_metadata.deSerialize(iss);
+				if(version <= 15)
+				{
+					std::string data = deSerializeString(is);
+					std::istringstream iss(data, std::ios_base::binary);
+					m_node_metadata.deSerialize(iss);
+				}
+				else
+				{
+					//std::string data = deSerializeLongString(is);
+					std::ostringstream oss(std::ios_base::binary);
+					decompressZlib(is, oss);
+					std::istringstream iss(oss.str(), std::ios_base::binary);
+					m_node_metadata.deSerialize(iss);
+				}
 			}
 			catch(SerializationError &e)
 			{

+ 28 - 1
src/player.cpp

@@ -33,6 +33,7 @@ Player::Player():
 	in_water_stable(false),
 	swimming_up(false),
 	craftresult_is_preview(true),
+	hp(20),
 	peer_id(PEER_ID_INEXISTENT),
 	m_pitch(0),
 	m_yaw(0),
@@ -102,6 +103,7 @@ void Player::serialize(std::ostream &os)
 	args.setFloat("yaw", m_yaw);
 	args.setV3F("position", m_position);
 	args.setBool("craftresult_is_preview", craftresult_is_preview);
+	args.setS32("hp", hp);
 
 	args.writeLines(os);
 
@@ -138,6 +140,11 @@ void Player::deSerialize(std::istream &is)
 	}catch(SettingNotFoundException &e){
 		craftresult_is_preview = true;
 	}
+	try{
+		hp = args.getS32("hp");
+	}catch(SettingNotFoundException &e){
+		hp = 20;
+	}
 
 	inventory.deSerialize(is);
 }
@@ -276,7 +283,8 @@ LocalPlayer::~LocalPlayer()
 {
 }
 
-void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
+void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
+		core::list<CollisionInfo> *collision_info)
 {
 	v3f position = getPosition();
 	v3f oldpos = position;
@@ -530,9 +538,23 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
 			*/
 			if(other_axes_overlap && main_axis_collides)
 			{
+				v3f old_speed = m_speed;
+
 				m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
 				position -= position.dotProduct(dirs[i]) * dirs[i];
 				position += oldpos.dotProduct(dirs[i]) * dirs[i];
+				
+				if(collision_info)
+				{
+					// Report fall collision
+					if(old_speed.Y < m_speed.Y - 0.1)
+					{
+						CollisionInfo info;
+						info.t = COLLISION_FALL;
+						info.speed = m_speed.Y - old_speed.Y;
+						collision_info->push_back(info);
+					}
+				}
 			}
 		
 		}
@@ -617,6 +639,11 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
 	setPosition(position);
 }
 
+void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
+{
+	move(dtime, map, pos_max_d, NULL);
+}
+
 void LocalPlayer::applyControl(float dtime)
 {
 	// Clear stuff

+ 5 - 0
src/player.h

@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "common_irrlicht.h"
 #include "inventory.h"
+#include "collision.h"
 
 #define PLAYERNAME_SIZE 20
 
@@ -124,6 +125,8 @@ public:
 
 	bool craftresult_is_preview;
 
+	u16 hp;
+
 	u16 peer_id;
 
 protected:
@@ -325,6 +328,8 @@ public:
 		return true;
 	}
 
+	void move(f32 dtime, Map &map, f32 pos_max_d,
+			core::list<CollisionInfo> *collision_info);
 	void move(f32 dtime, Map &map, f32 pos_max_d);
 
 	void applyControl(float dtime);

+ 6 - 0
src/serialization.cpp

@@ -105,6 +105,12 @@ void compressZlib(SharedBuffer<u8> data, std::ostream &os)
 
 }
 
+void compressZlib(const std::string &data, std::ostream &os)
+{
+	SharedBuffer<u8> databuf((u8*)data.c_str(), data.size());
+	compressZlib(databuf, os);
+}
+
 void decompressZlib(std::istream &is, std::ostream &os)
 {
 	z_stream z;

+ 7 - 1
src/serialization.h

@@ -48,17 +48,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 	13: (dev) Mapgen v2
 	14: (dev) NodeMetadata
 	15: (dev) StaticObjects
+	16: (dev) larger maximum size of node metadata, and compression
 */
 // This represents an uninitialized or invalid format
 #define SER_FMT_VER_INVALID 255
 // Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 15
+#define SER_FMT_VER_HIGHEST 16
 // Lowest supported serialization version
 #define SER_FMT_VER_LOWEST 0
 
 #define ser_ver_supported(v) (v >= SER_FMT_VER_LOWEST && v <= SER_FMT_VER_HIGHEST)
 
+void compressZlib(SharedBuffer<u8> data, std::ostream &os);
+void compressZlib(const std::string &data, std::ostream &os);
+void decompressZlib(std::istream &is, std::ostream &os);
+
 void compress(SharedBuffer<u8> data, std::ostream &os, u8 version);
+//void compress(const std::string &data, std::ostream &os, u8 version);
 void decompress(std::istream &is, std::ostream &os, u8 version);
 
 /*class Serializable

File diff suppressed because it is too large
+ 519 - 312
src/server.cpp


+ 27 - 0
src/server.h

@@ -33,6 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include "inventory.h"
 
+/*
+	Some random functions
+*/
+v3f findSpawnPos(ServerMap &map);
+
+/*
+	A structure containing the data needed for queueing the fetching
+	of blocks.
+*/
 struct QueuedBlockEmerge
 {
 	v3s16 pos;
@@ -397,12 +406,24 @@ private:
 	void peerAdded(con::Peer *peer);
 	void deletingPeer(con::Peer *peer, bool timeout);
 	
+	/*
+		Static send methods
+	*/
+	
+	static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
+	
+	/*
+		Non-static send methods
+	*/
+
 	// Envlock and conlock should be locked when calling these
 	void SendObjectData(float dtime);
 	void SendPlayerInfos();
 	void SendInventory(u16 peer_id);
 	void SendChatMessage(u16 peer_id, const std::wstring &message);
 	void BroadcastChatMessage(const std::wstring &message);
+	void SendPlayerHP(Player *player);
+	void SendMovePlayer(Player *player);
 	/*
 		Send a node removal/addition event to all clients except ignore_id.
 		Additionally, if far_players!=NULL, players further away than
@@ -418,6 +439,12 @@ private:
 	
 	// Sends blocks to clients
 	void SendBlocks(float dtime);
+
+	/*
+		Something random
+	*/
+	
+	void UpdateCrafting(u16 peer_id);
 	
 	// When called, connection mutex should be locked
 	RemoteClient* getClient(u16 peer_id);

+ 215 - 0
src/serverobject.cpp

@@ -451,4 +451,219 @@ InventoryItem* RatSAO::createPickedUpItem()
 	return item;
 }
 
+/*
+	Oerkki1SAO
+*/
+
+// Prototype
+Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
+
+Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
+	ServerActiveObject(env, id, pos),
+	m_is_active(false),
+	m_speed_f(0,0,0)
+{
+	ServerActiveObject::registerType(getType(), create);
+
+	m_oldpos = v3f(0,0,0);
+	m_last_sent_position = v3f(0,0,0);
+	m_yaw = 0;
+	m_counter1 = 0;
+	m_counter2 = 0;
+	m_age = 0;
+	m_touching_ground = false;
+	m_hp = 20;
+}
+
+ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
+		const std::string &data)
+{
+	std::istringstream is(data, std::ios::binary);
+	// read version
+	u8 version = readU8(is);
+	// read hp
+	u8 hp = readU8(is);
+	// check if version is supported
+	if(version != 0)
+		return NULL;
+	Oerkki1SAO *o = new Oerkki1SAO(env, id, pos);
+	o->m_hp = hp;
+	return o;
+}
+
+void Oerkki1SAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
+		bool send_recommended)
+{
+	assert(m_env);
+
+	if(m_is_active == false)
+	{
+		if(m_inactive_interval.step(dtime, 0.5)==false)
+			return;
+	}
+
+	/*
+		The AI
+	*/
+
+	m_age += dtime;
+	if(m_age > 60)
+	{
+		// Die
+		m_removed = true;
+		return;
+	}
+
+	// Apply gravity
+	m_speed_f.Y -= dtime*9.81*BS;
+
+	/*
+		Move around if some player is close
+	*/
+	bool player_is_close = false;
+	v3f near_player_pos;
+	// Check connected players
+	core::list<Player*> players = m_env->getPlayers(true);
+	core::list<Player*>::Iterator i;
+	for(i = players.begin();
+			i != players.end(); i++)
+	{
+		Player *player = *i;
+		v3f playerpos = player->getPosition();
+		if(m_base_position.getDistanceFrom(playerpos) < BS*15.0)
+		{
+			player_is_close = true;
+			near_player_pos = playerpos;
+			break;
+		}
+	}
+
+	m_is_active = player_is_close;
+	
+	if(player_is_close == false)
+	{
+		m_speed_f.X = 0;
+		m_speed_f.Z = 0;
+	}
+	else
+	{
+		// Move around
+
+		v3f ndir = near_player_pos - m_base_position;
+		ndir.Y = 0;
+		ndir /= ndir.getLength();
+		f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
+		if(nyaw < m_yaw - 180)
+			nyaw += 360;
+		else if(nyaw > m_yaw + 180)
+			nyaw -= 360;
+		m_yaw = 0.95*m_yaw + 0.05*nyaw;
+		m_yaw = wrapDegrees(m_yaw);
+
+		v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
+		f32 speed = 2*BS;
+		m_speed_f.X = speed * dir.X;
+		m_speed_f.Z = speed * dir.Z;
+
+		if(m_touching_ground && (m_oldpos - m_base_position).getLength()
+				< dtime*speed/2)
+		{
+			m_counter1 -= dtime;
+			if(m_counter1 < 0.0)
+			{
+				m_counter1 += 1.0;
+				// Jump
+				m_speed_f.Y = 5.0*BS;
+			}
+		}
+
+		{
+			m_counter2 -= dtime;
+			if(m_counter2 < 0.0)
+			{
+				m_counter2 += (float)(myrand()%100)/100*3.0;
+				//m_yaw += ((float)(myrand()%200)-100)/100*180;
+				m_yaw += ((float)(myrand()%200)-100)/100*90;
+				m_yaw = wrapDegrees(m_yaw);
+			}
+		}
+	}
+	
+	m_oldpos = m_base_position;
+
+	/*
+		Move it, with collision detection
+	*/
+
+	core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
+	collisionMoveResult moveresult;
+	// 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);
+	m_touching_ground = moveresult.touching_ground;
+	
+	setBasePosition(pos_f);
+
+	if(send_recommended == false)
+		return;
+
+	if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+	{
+		m_last_sent_position = pos_f;
+
+		std::ostringstream os(std::ios::binary);
+		// command (0 = update position)
+		writeU8(os, 0);
+		// pos
+		writeV3F1000(os, m_base_position);
+		// yaw
+		writeF1000(os, m_yaw);
+		// create message and add to list
+		ActiveObjectMessage aom(getId(), false, os.str());
+		messages.push_back(aom);
+	}
+}
+
+std::string Oerkki1SAO::getClientInitializationData()
+{
+	std::ostringstream os(std::ios::binary);
+	// version
+	writeU8(os, 0);
+	// pos
+	writeV3F1000(os, m_base_position);
+	return os.str();
+}
+
+std::string Oerkki1SAO::getStaticData()
+{
+	//dstream<<__FUNCTION_NAME<<std::endl;
+	std::ostringstream os(std::ios::binary);
+	// version
+	writeU8(os, 0);
+	// hp
+	writeU8(os, m_hp);
+	return os.str();
+}
+
+u16 Oerkki1SAO::punch(const std::string &toolname)
+{
+	u16 amount = 5;
+	if(amount < m_hp)
+	{
+		m_hp -= amount;
+	}
+	else
+	{
+		// Die
+		m_removed = true;
+	}
+	return 65536/100;
+}
+
 

+ 34 - 0
src/serverobject.h

@@ -100,6 +100,12 @@ public:
 	*/
 	virtual InventoryItem* createPickedUpItem(){return NULL;}
 	
+	/*
+		If the object doesn't return an item, this will be called.
+		Return value is tool wear.
+	*/
+	virtual u16 punch(const std::string &toolname){return 0;}
+	
 	// Number of players which know about this object
 	u16 m_known_by_count;
 	/*
@@ -201,5 +207,33 @@ private:
 	bool m_touching_ground;
 };
 
+class Oerkki1SAO : public ServerActiveObject
+{
+public:
+	Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos);
+	u8 getType() const
+		{return ACTIVEOBJECT_TYPE_OERKKI1;}
+	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+			const std::string &data);
+	void step(float dtime, Queue<ActiveObjectMessage> &messages,
+			bool send_recommended);
+	std::string getClientInitializationData();
+	std::string getStaticData();
+	InventoryItem* createPickedUpItem(){return NULL;}
+	u16 punch(const std::string &toolname);
+private:
+	bool m_is_active;
+	IntervalLimiter m_inactive_interval;
+	v3f m_speed_f;
+	v3f m_oldpos;
+	v3f m_last_sent_position;
+	float m_yaw;
+	float m_counter1;
+	float m_counter2;
+	float m_age;
+	bool m_touching_ground;
+	u8 m_hp;
+};
+
 #endif
 

+ 8 - 8
src/test.cpp

@@ -951,18 +951,18 @@ struct TestConnection
 			assert(got_exception);
 		}
 		{
-			//u8 data1[1100];
-			SharedBuffer<u8> data1(1100);
-			for(u16 i=0; i<1100; i++){
+			const int datasize = 30000;
+			SharedBuffer<u8> data1(datasize);
+			for(u16 i=0; i<datasize; i++){
 				data1[i] = i/4;
 			}
 
-			dstream<<"Sending data (size="<<1100<<"):";
-			for(int i=0; i<1100 && i<20; i++){
+			dstream<<"Sending data (size="<<datasize<<"):";
+			for(int i=0; i<datasize && i<20; i++){
 				if(i%2==0) DEBUGPRINT(" ");
 				DEBUGPRINT("%.2X", ((int)((const char*)*data1)[i])&0xff);
 			}
-			if(1100>20)
+			if(datasize>20)
 				dstream<<"...";
 			dstream<<std::endl;
 			
@@ -970,10 +970,10 @@ struct TestConnection
 
 			sleep_ms(50);
 			
-			u8 recvdata[2000];
+			u8 recvdata[datasize + 1000];
 			dstream<<"** running client.Receive()"<<std::endl;
 			u16 peer_id = 132;
-			u16 size = client.Receive(peer_id, recvdata, 2000);
+			u16 size = client.Receive(peer_id, recvdata, datasize + 1000);
 			dstream<<"** Client received: peer_id="<<peer_id
 					<<", size="<<size
 					<<std::endl;

+ 4 - 4
src/utility.h

@@ -215,8 +215,8 @@ inline void writeU16(std::ostream &os, u16 p)
 }
 inline u16 readU16(std::istream &is)
 {
-	char buf[12];
-	is.read(buf, 12);
+	char buf[2];
+	is.read(buf, 2);
 	return readU16((u8*)buf);
 }
 
@@ -228,8 +228,8 @@ inline void writeF1000(std::ostream &os, f32 p)
 }
 inline f32 readF1000(std::istream &is)
 {
-	char buf[12];
-	is.read(buf, 12);
+	char buf[2];
+	is.read(buf, 2);
 	return readF1000((u8*)buf);
 }
 

Some files were not shown because too many files changed in this diff