Some work-in-progress in hp and mobs and a frightening amount of random fixes.
authorPerttu Ahola <celeron55@gmail.com>
Thu, 21 Apr 2011 16:35:17 +0000 (19:35 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Thu, 21 Apr 2011 16:35:17 +0000 (19:35 +0300)
40 files changed:
data/heart.png [new file with mode: 0644]
data/oerkki1.png [new file with mode: 0644]
data/stick.png
data/tool_mesepick.png
data/tool_steelaxe.png
data/tool_steelpick.png
data/tool_steelshovel.png
data/tool_stoneaxe.png
data/tool_stonepick.png
data/tool_stoneshovel.png
data/tool_woodaxe.png
data/tool_woodpick.png
data/tool_woodshovel.png
minetest.conf.example
src/activeobject.h
src/client.cpp
src/client.h
src/clientobject.cpp
src/clientobject.h
src/clientserver.h
src/collision.cpp
src/collision.h
src/defaultsettings.cpp
src/environment.cpp
src/environment.h
src/inventory.h
src/main.cpp
src/map.cpp
src/map.h
src/mapblock.cpp
src/player.cpp
src/player.h
src/serialization.cpp
src/serialization.h
src/server.cpp
src/server.h
src/serverobject.cpp
src/serverobject.h
src/test.cpp
src/utility.h

diff --git a/data/heart.png b/data/heart.png
new file mode 100644 (file)
index 0000000..ddd273d
Binary files /dev/null and b/data/heart.png differ
diff --git a/data/oerkki1.png b/data/oerkki1.png
new file mode 100644 (file)
index 0000000..c32fb99
Binary files /dev/null and b/data/oerkki1.png differ
index 7a4663cc3a3ea2e9e4638205d831511abd4af67f..2d31797f00678eaf60a7c84536b20b3e30d743d1 100644 (file)
Binary files a/data/stick.png and b/data/stick.png differ
index 886f4b21c9cde5210568b1fdd6aaa29fe18b8320..a1f3812e0992e9b575f00944c0a2580ce78f640d 100644 (file)
Binary files a/data/tool_mesepick.png and b/data/tool_mesepick.png differ
index 85267ae7faec869b58df019acf493340c73107f5..390dbb0870e77abfbd49e2a99eca89518cd57f4d 100644 (file)
Binary files a/data/tool_steelaxe.png and b/data/tool_steelaxe.png differ
index 4bb5f8be47c38454304cdb073f8cebd9885c6559..7982dafebf650bcc5d6492e33212365f57625d7c 100644 (file)
Binary files a/data/tool_steelpick.png and b/data/tool_steelpick.png differ
index 61d90b12aec382341207ccb67c51bccd34961920..ed8413846005dfb5d02ada350a4e2c088c566cc8 100644 (file)
Binary files a/data/tool_steelshovel.png and b/data/tool_steelshovel.png differ
index bcb5896893e0dcb8c1305ed9b45241212ee10744..0c5414af570340c9d9454ff53f8afc6f2c4c5cce 100644 (file)
Binary files a/data/tool_stoneaxe.png and b/data/tool_stoneaxe.png differ
index 9ca3a5e03524a653dfebbb28e6ba63d25443fc07..b34de6f327a633d5127acaf39974c4a8aac219ec 100644 (file)
Binary files a/data/tool_stonepick.png and b/data/tool_stonepick.png differ
index 53eb72307e20e7ba1f03ce63add91acdbc8a56ec..ba5243101a1180a6f5f07f0fb791dae2c1e9416f 100644 (file)
Binary files a/data/tool_stoneshovel.png and b/data/tool_stoneshovel.png differ
index cb0d95f28ffd92900cfa054b2d5b41e4b2e4ccd3..34f54eff966ad5dc9398a1b45fbec8d403022eed 100644 (file)
Binary files a/data/tool_woodaxe.png and b/data/tool_woodaxe.png differ
index 3592495154f62365e3adf6b6941dec31c793772d..ea728cca3fd583d1cc76a702ea48b7f0961fd51a 100644 (file)
Binary files a/data/tool_woodpick.png and b/data/tool_woodpick.png differ
index 2645952d00b260701eafc2fad6f125ed9afebf90..649ab4c38a79fb48376ed13949ae5e182d328cd0 100644 (file)
Binary files a/data/tool_woodshovel.png and b/data/tool_woodshovel.png differ
index c78266e7bb0353139decd210eb95646882f703d9..02cfb7aada1b296fd68f51830f933447653a4c38 100644 (file)
@@ -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
 
index e1fc6beaf1ee3d71d8e76e6486b56f63d1f8b7a3..382f7f7981d329a3b751da08e44362b5f3a50df2 100644 (file)
@@ -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
index e2877f5fc63434ed123b68df5bb6afd4a29f7d37..702247f66364aace840cc3bf12ba6ae417903caa 100644 (file)
@@ -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();
+}
+
+
index ef3dd435a04b5692dd49dfea576456da82e87893..ee73cc42ce83a1e6d3e61076ae84e1e5cd881700 100644 (file)
@@ -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
index 5b744de6ce0d99b4c6490503e46002e68ab244fe..78258add88bce8cb1fdcc4cbf5806c16ac6054c8 100644 (file)
@@ -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();
+}
+
 
index 569e9eca6905857cfa69943fd34c28a8eccdff4c..8d211fef38dde5a9f8f59443e688fcf6b61c880f 100644 (file)
@@ -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
 
index fadafed5fe4dbe53b82a0dc7794eaacd9eea476d..46ffa5eab365d25281356840a2fdb04f2cef9e5a 100644 (file)
@@ -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)
index 83cefe4d1e1a5db78db65a18281b4e0c46b4caab..63186a84a5e72a2b803777f4c8795d652b5097b9 100644 (file)
@@ -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++)
index 17243140148a8686e1a1fe50974935816979eb6c..9c913c6a9720d52116fadc58060a4eb2bb32a744 100644 (file)
@@ -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
 
index 2a548d406e3a85155bb88151d9f6b58b33c7565b..b5d86391414b22cc62fb466ec4871b51f73ca516 100644 (file)
@@ -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");
index 3f95ed9f9be7f3c71d480c084f80868f4ffc9508..b3055ca6f7b88b3d83a8daec93407f830db446c7 100644 (file)
@@ -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
 
index e82cea6ae275ab9fe2330b543397b8bfa4431a60..00192d26278d1bb8a4b23c5900a264a4b2980df9 100644 (file)
@@ -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
index d2d23542ea3c95002d16b66a66c8c7b7c3379a54..f162952d32f19320c6edb16f886066648f09f7c6 100644 (file)
@@ -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";
                
index bf5f3182b36c0e0a45c8dce234cd83dccfb9daaa..436e5babc9557cfdf908adefc14a1b0c6a392ccf 100644 (file)
@@ -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\r
       bartwe's game\r
 \r
+SUGG: Background music based on cellular automata?\r
+      http://www.earslap.com/projectslab/otomata\r
+\r
+\r
 Gaming ideas:\r
 -------------\r
 \r
@@ -126,6 +130,12 @@ Game content:
        - You can drop on top of it, and have some time to attack there\r
          before he shakes you off\r
 \r
+- Maybe the difficulty could come from monsters getting tougher in\r
+  far-away places, and the player starting to need something from\r
+  there when time goes by.\r
+  - The player would have some of that stuff at the beginning, and\r
+    would need new supplies of it when it runs out\r
+\r
 Documentation:\r
 --------------\r
 \r
@@ -1210,7 +1220,7 @@ void updateViewingRange(f32 frametime_in, Client *client)
 \r
 void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,\r
                v2s32 centerlowerpos, s32 imgsize, s32 itemcount,\r
-               Inventory *inventory)\r
+               Inventory *inventory, s32 halfheartcount)\r
 {\r
        InventoryList *mainlist = inventory->getList("main");\r
        if(mainlist == NULL)\r
@@ -1259,6 +1269,40 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
                        drawInventoryItem(driver, font, item, rect, NULL);\r
                }\r
        }\r
+       \r
+       /*\r
+               Draw hearts\r
+       */\r
+       {\r
+               video::ITexture *heart_texture =\r
+                               driver->getTexture(porting::getDataPath("heart.png").c_str());\r
+               v2s32 p = pos + v2s32(0, -20);\r
+               for(s32 i=0; i<halfheartcount/2; i++)\r
+               {\r
+                       const video::SColor color(255,255,255,255);\r
+                       const video::SColor colors[] = {color,color,color,color};\r
+                       core::rect<s32> rect(0,0,16,16);\r
+                       rect += p;\r
+                       driver->draw2DImage(heart_texture, rect,\r
+                               core::rect<s32>(core::position2d<s32>(0,0),\r
+                               core::dimension2di(heart_texture->getOriginalSize())),\r
+                               NULL, colors, true);\r
+                       p += v2s32(20,0);\r
+               }\r
+               if(halfheartcount % 2 == 1)\r
+               {\r
+                       const video::SColor color(255,255,255,255);\r
+                       const video::SColor colors[] = {color,color,color,color};\r
+                       core::rect<s32> rect(0,0,16/2,16);\r
+                       rect += p;\r
+                       core::dimension2di srcd(heart_texture->getOriginalSize());\r
+                       srcd.Width /= 2;\r
+                       driver->draw2DImage(heart_texture, rect,\r
+                               core::rect<s32>(core::position2d<s32>(0,0), srcd),\r
+                               NULL, colors, true);\r
+                       p += v2s32(20,0);\r
+               }\r
+       }\r
 }\r
 \r
 #if 0\r
@@ -1519,6 +1563,215 @@ void SpeedTests()
        }\r
 }\r
 \r
+void getPointedNode(v3f player_position,\r
+               v3f camera_direction, v3f camera_position,\r
+               bool &nodefound, core::line3d<f32> shootline,\r
+               v3s16 &nodepos, v3s16 &neighbourpos,\r
+               core::aabbox3d<f32> &nodehilightbox,\r
+               f32 d)\r
+{\r
+       assert(g_client);\r
+\r
+       f32 mindistance = BS * 1001;\r
+       \r
+       v3s16 pos_i = floatToInt(player_position, BS);\r
+\r
+       /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"\r
+                       <<std::endl;*/\r
+\r
+       s16 a = d;\r
+       s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);\r
+       s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);\r
+       s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);\r
+       s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);\r
+       s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);\r
+       s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);\r
+       \r
+       for(s16 y = ystart; y <= yend; y++)\r
+       for(s16 z = zstart; z <= zend; z++)\r
+       for(s16 x = xstart; x <= xend; x++)\r
+       {\r
+               MapNode n;\r
+               try\r
+               {\r
+                       n = g_client->getNode(v3s16(x,y,z));\r
+                       if(content_pointable(n.d) == false)\r
+                               continue;\r
+               }\r
+               catch(InvalidPositionException &e)\r
+               {\r
+                       continue;\r
+               }\r
+\r
+               v3s16 np(x,y,z);\r
+               v3f npf = intToFloat(np, BS);\r
+               \r
+               f32 d = 0.01;\r
+               \r
+               v3s16 dirs[6] = {\r
+                       v3s16(0,0,1), // back\r
+                       v3s16(0,1,0), // top\r
+                       v3s16(1,0,0), // right\r
+                       v3s16(0,0,-1), // front\r
+                       v3s16(0,-1,0), // bottom\r
+                       v3s16(-1,0,0), // left\r
+               };\r
+               \r
+               /*\r
+                       Meta-objects\r
+               */\r
+               if(n.d == CONTENT_TORCH)\r
+               {\r
+                       v3s16 dir = unpackDir(n.dir);\r
+                       v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
+                       dir_f *= BS/2 - BS/6 - BS/20;\r
+                       v3f cpf = npf + dir_f;\r
+                       f32 distance = (cpf - camera_position).getLength();\r
+\r
+                       core::aabbox3d<f32> box;\r
+                       \r
+                       // bottom\r
+                       if(dir == v3s16(0,-1,0))\r
+                       {\r
+                               box = core::aabbox3d<f32>(\r
+                                       npf - v3f(BS/6, BS/2, BS/6),\r
+                                       npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)\r
+                               );\r
+                       }\r
+                       // top\r
+                       else if(dir == v3s16(0,1,0))\r
+                       {\r
+                               box = core::aabbox3d<f32>(\r
+                                       npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),\r
+                                       npf + v3f(BS/6, BS/2, BS/6)\r
+                               );\r
+                       }\r
+                       // side\r
+                       else\r
+                       {\r
+                               box = core::aabbox3d<f32>(\r
+                                       cpf - v3f(BS/6, BS/3, BS/6),\r
+                                       cpf + v3f(BS/6, BS/3, BS/6)\r
+                               );\r
+                       }\r
+\r
+                       if(distance < mindistance)\r
+                       {\r
+                               if(box.intersectsWithLine(shootline))\r
+                               {\r
+                                       nodefound = true;\r
+                                       nodepos = np;\r
+                                       neighbourpos = np;\r
+                                       mindistance = distance;\r
+                                       nodehilightbox = box;\r
+                               }\r
+                       }\r
+               }\r
+               else if(n.d == CONTENT_SIGN_WALL)\r
+               {\r
+                       v3s16 dir = unpackDir(n.dir);\r
+                       v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
+                       dir_f *= BS/2 - BS/6 - BS/20;\r
+                       v3f cpf = npf + dir_f;\r
+                       f32 distance = (cpf - camera_position).getLength();\r
+\r
+                       v3f vertices[4] =\r
+                       {\r
+                               v3f(BS*0.42,-BS*0.35,-BS*0.4),\r
+                               v3f(BS*0.49, BS*0.35, BS*0.4),\r
+                       };\r
+\r
+                       for(s32 i=0; i<2; i++)\r
+                       {\r
+                               if(dir == v3s16(1,0,0))\r
+                                       vertices[i].rotateXZBy(0);\r
+                               if(dir == v3s16(-1,0,0))\r
+                                       vertices[i].rotateXZBy(180);\r
+                               if(dir == v3s16(0,0,1))\r
+                                       vertices[i].rotateXZBy(90);\r
+                               if(dir == v3s16(0,0,-1))\r
+                                       vertices[i].rotateXZBy(-90);\r
+                               if(dir == v3s16(0,-1,0))\r
+                                       vertices[i].rotateXYBy(-90);\r
+                               if(dir == v3s16(0,1,0))\r
+                                       vertices[i].rotateXYBy(90);\r
+\r
+                               vertices[i] += npf;\r
+                       }\r
+\r
+                       core::aabbox3d<f32> box;\r
+\r
+                       box = core::aabbox3d<f32>(vertices[0]);\r
+                       box.addInternalPoint(vertices[1]);\r
+\r
+                       if(distance < mindistance)\r
+                       {\r
+                               if(box.intersectsWithLine(shootline))\r
+                               {\r
+                                       nodefound = true;\r
+                                       nodepos = np;\r
+                                       neighbourpos = np;\r
+                                       mindistance = distance;\r
+                                       nodehilightbox = box;\r
+                               }\r
+                       }\r
+               }\r
+               /*\r
+                       Regular blocks\r
+               */\r
+               else\r
+               {\r
+                       for(u16 i=0; i<6; i++)\r
+                       {\r
+                               v3f dir_f = v3f(dirs[i].X,\r
+                                               dirs[i].Y, dirs[i].Z);\r
+                               v3f centerpoint = npf + dir_f * BS/2;\r
+                               f32 distance =\r
+                                               (centerpoint - camera_position).getLength();\r
+                               \r
+                               if(distance < mindistance)\r
+                               {\r
+                                       core::CMatrix4<f32> m;\r
+                                       m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
+\r
+                                       // This is the back face\r
+                                       v3f corners[2] = {\r
+                                               v3f(BS/2, BS/2, BS/2),\r
+                                               v3f(-BS/2, -BS/2, BS/2+d)\r
+                                       };\r
+                                       \r
+                                       for(u16 j=0; j<2; j++)\r
+                                       {\r
+                                               m.rotateVect(corners[j]);\r
+                                               corners[j] += npf;\r
+                                       }\r
+\r
+                                       core::aabbox3d<f32> facebox(corners[0]);\r
+                                       facebox.addInternalPoint(corners[1]);\r
+\r
+                                       if(facebox.intersectsWithLine(shootline))\r
+                                       {\r
+                                               nodefound = true;\r
+                                               nodepos = np;\r
+                                               neighbourpos = np + dirs[i];\r
+                                               mindistance = distance;\r
+\r
+                                               //nodehilightbox = facebox;\r
+\r
+                                               const float d = 0.502;\r
+                                               core::aabbox3d<f32> nodebox\r
+                                                               (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
+                                               v3f nodepos_f = intToFloat(nodepos, BS);\r
+                                               nodebox.MinEdge += nodepos_f;\r
+                                               nodebox.MaxEdge += nodepos_f;\r
+                                               nodehilightbox = nodebox;\r
+                                       }\r
+                               } // if distance < mindistance\r
+                       } // for dirs\r
+               } // regular block\r
+       } // for coords\r
+}\r
+\r
 int main(int argc, char *argv[])\r
 {\r
        /*\r
@@ -2148,30 +2401,14 @@ int main(int argc, char *argv[])
 \r
        //video::SColor skycolor = video::SColor(255,90,140,200);\r
        //video::SColor skycolor = video::SColor(255,166,202,244);\r
-       video::SColor skycolor = video::SColor(255,120,185,244);\r
+       //video::SColor skycolor = video::SColor(255,120,185,244);\r
+       video::SColor skycolor = video::SColor(255,140,186,250);\r
 \r
        camera->setFOV(FOV_ANGLE);\r
 \r
        // Just so big a value that everything rendered is visible\r
        camera->setFarValue(100000*BS);\r
        \r
-       /*\r
-               Lighting test code. Doesn't quite work this way.\r
-               The CPU-computed lighting is good.\r
-       */\r
-\r
-       /*\r
-       smgr->addLightSceneNode(NULL,\r
-               v3f(0, BS*1000000, 0),\r
-               video::SColorf(0.3,0.3,0.3),\r
-               BS*10000000);\r
-\r
-       smgr->setAmbientLight(video::SColorf(0.0, 0.0, 0.0));\r
-\r
-       scene::ILightSceneNode *light = smgr->addLightSceneNode(camera,\r
-                       v3f(0, 0, 0), video::SColorf(0.5,0.5,0.5), BS*4);\r
-       */\r
-\r
        f32 camera_yaw = 0; // "right/left"\r
        f32 camera_pitch = 0; // "up/down"\r
 \r
@@ -2226,6 +2463,8 @@ int main(int argc, char *argv[])
 \r
        core::list<float> frametime_log;\r
 \r
+       float damage_flash_timer = 0;\r
+\r
        /*\r
                Main loop\r
        */\r
@@ -2453,6 +2692,16 @@ int main(int argc, char *argv[])
                        );\r
                        client.setPlayerControl(control);\r
                }\r
+               \r
+               /*\r
+                       Run server\r
+               */\r
+\r
+               if(server != NULL)\r
+               {\r
+                       //TimeTaker timer("server->step(dtime)");\r
+                       server->step(dtime);\r
+               }\r
 \r
                /*\r
                        Process environment\r
@@ -2464,12 +2713,28 @@ int main(int argc, char *argv[])
                        //client.step(dtime_avg1);\r
                }\r
 \r
-               if(server != NULL)\r
+               // Read client events\r
+               for(;;)\r
                {\r
-                       //TimeTaker timer("server->step(dtime)");\r
-                       server->step(dtime);\r
+                       ClientEvent event = client.getClientEvent();\r
+                       if(event.type == CE_NONE)\r
+                       {\r
+                               break;\r
+                       }\r
+                       else if(event.type == CE_PLAYER_DAMAGE)\r
+                       {\r
+                               //u16 damage = event.player_damage.amount;\r
+                               //dstream<<"Player damage: "<<damage<<std::endl;\r
+                               damage_flash_timer = 0.05;\r
+                       }\r
+                       else if(event.type == CE_PLAYER_FORCE_MOVE)\r
+                       {\r
+                               camera_yaw = event.player_force_move.yaw;\r
+                               camera_pitch = event.player_force_move.pitch;\r
+                       }\r
                }\r
-\r
+               \r
+               // Get player position\r
                v3f player_position = client.getPlayerPosition();\r
                \r
                //TimeTaker //timer2("//timer2");\r
@@ -2637,22 +2902,6 @@ int main(int argc, char *argv[])
                        else if(g_input->getRightClicked())\r
                        {\r
                                std::cout<<DTIME<<"Right-clicked object"<<std::endl;\r
-#if 0\r
-                               /*\r
-                                       Check if we want to modify the object ourselves\r
-                               */\r
-                               if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)\r
-                               {\r
-                               }\r
-                               /*\r
-                                       Otherwise pass the event to the server as-is\r
-                               */\r
-                               else\r
-                               {\r
-                                       client.clickObject(1, selected_object->getBlock()->getPos(),\r
-                                                       selected_object->getId(), g_selected_item);\r
-                               }\r
-#endif\r
                        }\r
                }\r
                else // selected_object == NULL\r
@@ -2666,205 +2915,13 @@ int main(int argc, char *argv[])
                v3s16 nodepos;\r
                v3s16 neighbourpos;\r
                core::aabbox3d<f32> nodehilightbox;\r
-               f32 mindistance = BS * 1001;\r
-               \r
-               v3s16 pos_i = floatToInt(player_position, BS);\r
-\r
-               /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"\r
-                               <<std::endl;*/\r
-\r
-               s16 a = d;\r
-               s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);\r
-               s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);\r
-               s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);\r
-               s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);\r
-               s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);\r
-               s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);\r
-               \r
-               for(s16 y = ystart; y <= yend; y++)\r
-               for(s16 z = zstart; z <= zend; z++)\r
-               for(s16 x = xstart; x <= xend; x++)\r
-               {\r
-                       MapNode n;\r
-                       try\r
-                       {\r
-                               n = client.getNode(v3s16(x,y,z));\r
-                               if(content_pointable(n.d) == false)\r
-                                       continue;\r
-                       }\r
-                       catch(InvalidPositionException &e)\r
-                       {\r
-                               continue;\r
-                       }\r
-\r
-                       v3s16 np(x,y,z);\r
-                       v3f npf = intToFloat(np, BS);\r
-                       \r
-                       f32 d = 0.01;\r
-                       \r
-                       v3s16 dirs[6] = {\r
-                               v3s16(0,0,1), // back\r
-                               v3s16(0,1,0), // top\r
-                               v3s16(1,0,0), // right\r
-                               v3s16(0,0,-1), // front\r
-                               v3s16(0,-1,0), // bottom\r
-                               v3s16(-1,0,0), // left\r
-                       };\r
-                       \r
-                       /*\r
-                               Meta-objects\r
-                       */\r
-                       if(n.d == CONTENT_TORCH)\r
-                       {\r
-                               v3s16 dir = unpackDir(n.dir);\r
-                               v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
-                               dir_f *= BS/2 - BS/6 - BS/20;\r
-                               v3f cpf = npf + dir_f;\r
-                               f32 distance = (cpf - camera_position).getLength();\r
-\r
-                               core::aabbox3d<f32> box;\r
-                               \r
-                               // bottom\r
-                               if(dir == v3s16(0,-1,0))\r
-                               {\r
-                                       box = core::aabbox3d<f32>(\r
-                                               npf - v3f(BS/6, BS/2, BS/6),\r
-                                               npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)\r
-                                       );\r
-                               }\r
-                               // top\r
-                               else if(dir == v3s16(0,1,0))\r
-                               {\r
-                                       box = core::aabbox3d<f32>(\r
-                                               npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),\r
-                                               npf + v3f(BS/6, BS/2, BS/6)\r
-                                       );\r
-                               }\r
-                               // side\r
-                               else\r
-                               {\r
-                                       box = core::aabbox3d<f32>(\r
-                                               cpf - v3f(BS/6, BS/3, BS/6),\r
-                                               cpf + v3f(BS/6, BS/3, BS/6)\r
-                                       );\r
-                               }\r
-\r
-                               if(distance < mindistance)\r
-                               {\r
-                                       if(box.intersectsWithLine(shootline))\r
-                                       {\r
-                                               nodefound = true;\r
-                                               nodepos = np;\r
-                                               neighbourpos = np;\r
-                                               mindistance = distance;\r
-                                               nodehilightbox = box;\r
-                                       }\r
-                               }\r
-                       }\r
-                       else if(n.d == CONTENT_SIGN_WALL)\r
-                       {\r
-                               v3s16 dir = unpackDir(n.dir);\r
-                               v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
-                               dir_f *= BS/2 - BS/6 - BS/20;\r
-                               v3f cpf = npf + dir_f;\r
-                               f32 distance = (cpf - camera_position).getLength();\r
-\r
-                               v3f vertices[4] =\r
-                               {\r
-                                       v3f(BS*0.42,-BS*0.35,-BS*0.4),\r
-                                       v3f(BS*0.49, BS*0.35, BS*0.4),\r
-                               };\r
-\r
-                               for(s32 i=0; i<2; i++)\r
-                               {\r
-                                       if(dir == v3s16(1,0,0))\r
-                                               vertices[i].rotateXZBy(0);\r
-                                       if(dir == v3s16(-1,0,0))\r
-                                               vertices[i].rotateXZBy(180);\r
-                                       if(dir == v3s16(0,0,1))\r
-                                               vertices[i].rotateXZBy(90);\r
-                                       if(dir == v3s16(0,0,-1))\r
-                                               vertices[i].rotateXZBy(-90);\r
-                                       if(dir == v3s16(0,-1,0))\r
-                                               vertices[i].rotateXYBy(-90);\r
-                                       if(dir == v3s16(0,1,0))\r
-                                               vertices[i].rotateXYBy(90);\r
-\r
-                                       vertices[i] += npf;\r
-                               }\r
-\r
-                               core::aabbox3d<f32> box;\r
-\r
-                               box = core::aabbox3d<f32>(vertices[0]);\r
-                               box.addInternalPoint(vertices[1]);\r
-\r
-                               if(distance < mindistance)\r
-                               {\r
-                                       if(box.intersectsWithLine(shootline))\r
-                                       {\r
-                                               nodefound = true;\r
-                                               nodepos = np;\r
-                                               neighbourpos = np;\r
-                                               mindistance = distance;\r
-                                               nodehilightbox = box;\r
-                                       }\r
-                               }\r
-                       }\r
-                       /*\r
-                               Regular blocks\r
-                       */\r
-                       else\r
-                       {\r
-                               for(u16 i=0; i<6; i++)\r
-                               {\r
-                                       v3f dir_f = v3f(dirs[i].X,\r
-                                                       dirs[i].Y, dirs[i].Z);\r
-                                       v3f centerpoint = npf + dir_f * BS/2;\r
-                                       f32 distance =\r
-                                                       (centerpoint - camera_position).getLength();\r
-                                       \r
-                                       if(distance < mindistance)\r
-                                       {\r
-                                               core::CMatrix4<f32> m;\r
-                                               m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
-\r
-                                               // This is the back face\r
-                                               v3f corners[2] = {\r
-                                                       v3f(BS/2, BS/2, BS/2),\r
-                                                       v3f(-BS/2, -BS/2, BS/2+d)\r
-                                               };\r
-                                               \r
-                                               for(u16 j=0; j<2; j++)\r
-                                               {\r
-                                                       m.rotateVect(corners[j]);\r
-                                                       corners[j] += npf;\r
-                                               }\r
-\r
-                                               core::aabbox3d<f32> facebox(corners[0]);\r
-                                               facebox.addInternalPoint(corners[1]);\r
-\r
-                                               if(facebox.intersectsWithLine(shootline))\r
-                                               {\r
-                                                       nodefound = true;\r
-                                                       nodepos = np;\r
-                                                       neighbourpos = np + dirs[i];\r
-                                                       mindistance = distance;\r
-\r
-                                                       //nodehilightbox = facebox;\r
-\r
-                                                       const float d = 0.502;\r
-                                                       core::aabbox3d<f32> nodebox\r
-                                                                       (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
-                                                       v3f nodepos_f = intToFloat(nodepos, BS);\r
-                                                       nodebox.MinEdge += nodepos_f;\r
-                                                       nodebox.MaxEdge += nodepos_f;\r
-                                                       nodehilightbox = nodebox;\r
-                                               }\r
-                                       } // if distance < mindistance\r
-                               } // for dirs\r
-                       } // regular block\r
-               } // for coords\r
 \r
+               getPointedNode(player_position,\r
+                               camera_direction, camera_position,\r
+                               nodefound, shootline,\r
+                               nodepos, neighbourpos,\r
+                               nodehilightbox, d);\r
+       \r
                static float nodig_delay_counter = 0.0;\r
 \r
                if(nodefound)\r
@@ -3430,10 +3487,26 @@ int main(int argc, char *argv[])
                */\r
                {\r
                        draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),\r
-                                       hotbar_imagesize, hotbar_itemcount, &local_inventory);\r
+                                       hotbar_imagesize, hotbar_itemcount, &local_inventory,\r
+                                       client.getHP());\r
+               }\r
+\r
+               /*\r
+                       Damage flash\r
+               */\r
+               if(damage_flash_timer > 0.0)\r
+               {\r
+                       damage_flash_timer -= dtime;\r
+                       \r
+                       video::SColor color(128,255,0,0);\r
+                       driver->draw2DRectangle(color,\r
+                                       core::rect<s32>(0,0,screensize.X,screensize.Y),\r
+                                       NULL);\r
                }\r
                \r
-               // End drawing\r
+               /*\r
+                       End scene\r
+               */\r
                {\r
                        TimeTaker timer("endScene");\r
                        driver->endScene();\r
index 2a92f6733072d663ea336b64420c07962ef6161a..7e4fc4f47313abbe2e450c5aa37aa085eadd1e2a 100644 (file)
@@ -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);
                }
        }
index 206dc7d7ba31ee071903b7e1e1df7c711de56236..1cd021f52b9eeaeea3fb94da1058976e6c3d5531 100644 (file)
--- a/src/map.h
+++ b/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;
 };
index 38c081eec9d58ea3dc9d77ae750931eff58a0d77..5b8bc7b9f80762b0e818574fe158789e641c7e3b 100644 (file)
@@ -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)
                        {
index 8f594eee638ee89d75673b7a2e07494167993c48..31415b6b279481f4b88d48faf1d0439f3d870150 100644 (file)
@@ -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
index 2eaeaae9a6cfdf6e9ce7f03371d2467676e931c7..03fba1e2c0b252870aa9300efb5fd865d724910d 100644 (file)
@@ -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);
index c324ca0fdb13ef38deb917ce93a595d8914305af..6a43d9190f602867508a642d7356a76f7003db2d 100644 (file)
@@ -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;
index c87162e69ea6e5def223c3f9f055c859f5c3b6a3..c7cafc5d19306e60a87ed86acb8417a9e420ba9c 100644 (file)
@@ -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
index 154603a47099b27401aef105c5e0030ae6e26b4c..ee7a035e6bdae42b0bfa1b7028fafddde5c82025 100644 (file)
@@ -959,6 +959,8 @@ Server::Server(
 
 Server::~Server()
 {
+       dstream<<"Server::~Server()"<<std::endl;
+
        /*
                Send shutdown message
        */
@@ -980,13 +982,18 @@ Server::~Server()
                        if(client->serialization_version == SER_FMT_VER_INVALID)
                                continue;
 
-                       SendChatMessage(client->peer_id, line);
+                       try{
+                               SendChatMessage(client->peer_id, line);
+                       }
+                       catch(con::PeerNotFoundException &e)
+                       {}
                }
        }
 
        /*
                Save players
        */
+       dstream<<"Server: Saving players"<<std::endl;
        m_env.serializePlayers(m_mapsavedir);
        
        /*
@@ -1046,11 +1053,6 @@ void Server::stop()
        m_emergethread.stop();
        
        dout_server<<"Server: Threads stopped"<<std::endl;
-
-       dout_server<<"Server: Saving players"<<std::endl;
-       // Save players
-       // FIXME: Apparently this does not do anything here
-       //m_env.serializePlayers(m_mapsavedir);
 }
 
 void Server::step(float dtime)
@@ -1550,6 +1552,8 @@ void Server::AsyncRunStep()
                Step node metadata
        */
        {
+               //TimeTaker timer("Step node metadata");
+
                JMutexAutoLock envlock(m_env_mutex);
                JMutexAutoLock conlock(m_con_mutex);
                
@@ -1781,20 +1785,30 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        data[20+3-1] = 0;
                        player->updateName((const char*)&data[3]);
                }*/
-
-               // Now answer with a TOCLIENT_INIT
                
-               SharedBuffer<u8> reply(2+1+6+8);
-               writeU16(&reply[0], TOCLIENT_INIT);
-               writeU8(&reply[2], deployed);
-               writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
-               //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
-               
-               // Send as reliable
-               m_con.Send(peer_id, 0, reply, true);
+               /*
+                       Answer with a TOCLIENT_INIT
+               */
+               {
+                       SharedBuffer<u8> reply(2+1+6+8);
+                       writeU16(&reply[0], TOCLIENT_INIT);
+                       writeU8(&reply[2], deployed);
+                       writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
+                       //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
+                       writeU64(&reply[2+1+6], 0); // no seed
+                       
+                       // Send as reliable
+                       m_con.Send(peer_id, 0, reply, true);
+               }
+
+               /*
+                       Send complete position information
+               */
+               SendMovePlayer(player);
 
                return;
        }
+
        if(command == TOSERVER_INIT2)
        {
                derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
@@ -1812,7 +1826,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                SendPlayerInfos();
 
                // Send inventory to player
+               UpdateCrafting(peer->id);
                SendInventory(peer->id);
+
+               // Send HP
+               {
+                       Player *player = m_env.getPlayer(peer_id);
+                       SendPlayerHP(player);
+               }
                
                // Send time of day
                {
@@ -2005,6 +2026,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                
                                // Add to inventory and send inventory
                                ilist->addItem(item);
+                               UpdateCrafting(player->peer_id);
                                SendInventory(player->peer_id);
                        }
 
@@ -2026,7 +2048,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                */
                u8 button = readU8(&data[2]);
                u16 id = readS16(&data[3]);
-               //u16 item_i = readU16(&data[11]);
+               u16 item_i = readU16(&data[11]);
        
                ServerActiveObject *obj = m_env.getActiveObject(id);
 
@@ -2066,11 +2088,42 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                {
                                        // Add to inventory and send inventory
                                        ilist->addItem(item);
+                                       UpdateCrafting(player->peer_id);
                                        SendInventory(player->peer_id);
 
                                        // Remove object from environment
                                        obj->m_removed = true;
                                }
+                               else
+                               {
+                                       /*
+                                               Item cannot be picked up. Punch it instead.
+                                       */
+
+                                       ToolItem *titem = NULL;
+                                       std::string toolname = "";
+
+                                       InventoryList *mlist = player->inventory.getList("main");
+                                       if(mlist != NULL)
+                                       {
+                                               InventoryItem *item = mlist->getItem(item_i);
+                                               if(item && (std::string)item->getName() == "ToolItem")
+                                               {
+                                                       titem = (ToolItem*)item;
+                                                       toolname = titem->getToolName();
+                                               }
+                                       }
+                                       
+                                       u16 wear = obj->punch(toolname);
+                                       
+                                       if(titem)
+                                       {
+                                               bool weared_out = titem->addWear(wear);
+                                               if(weared_out)
+                                                       mlist->deleteItem(item_i);
+                                               SendInventory(player->peer_id);
+                                       }
+                               }
                        }
                }
        }
@@ -2276,6 +2329,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        player->inventory.addItem("main", item);
 
                                        // Send inventory
+                                       UpdateCrafting(player->peer_id);
                                        SendInventory(player->peer_id);
                                }
                        }
@@ -2380,6 +2434,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        else
                                                mitem->remove(1);
                                        // Send inventory
+                                       UpdateCrafting(peer_id);
                                        SendInventory(peer_id);
                                }
                                
@@ -2492,6 +2547,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                        item->remove(dropcount);
                                                
                                                // Send inventory
+                                               UpdateCrafting(peer_id);
                                                SendInventory(peer_id);
                                        }
                                }
@@ -2711,6 +2767,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        else
                        {
                                // Send inventory
+                               UpdateCrafting(player->peer_id);
                                SendInventory(player->peer_id);
                        }
                }
@@ -2856,6 +2913,36 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        }
                }
        }
+       else if(command == TOSERVER_DAMAGE)
+       {
+               if(g_settings.getBool("enable_damage"))
+               {
+                       std::string datastring((char*)&data[2], datasize-2);
+                       std::istringstream is(datastring, std::ios_base::binary);
+                       u8 damage = readU8(is);
+                       if(player->hp > damage)
+                       {
+                               player->hp -= damage;
+                       }
+                       else
+                       {
+                               player->hp = 0;
+
+                               dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
+                                               <<std::endl;
+                               
+                               v3f pos = findSpawnPos(m_env.getServerMap());
+                               player->setPosition(pos);
+                               player->hp = 20;
+                               SendMovePlayer(player);
+                               SendPlayerHP(player);
+                               
+                               //TODO: Throw items around
+                       }
+               }
+
+               SendPlayerHP(player);
+       }
        else
        {
                derr_server<<"WARNING: Server::ProcessData(): Ignoring "
@@ -2914,6 +3001,7 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
        {
                assert(c->current_player);
                // Send inventory
+               UpdateCrafting(c->current_player->peer_id);
                SendInventory(c->current_player->peer_id);
                return;
        }
@@ -3016,6 +3104,29 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
        m_peer_change_queue.push_back(c);
 }
 
+/*
+       Static send methods
+*/
+
+void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
+{
+       DSTACK(__FUNCTION_NAME);
+       std::ostringstream os(std::ios_base::binary);
+
+       writeU16(os, TOCLIENT_HP);
+       writeU8(os, hp);
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       con.Send(peer_id, 0, data, true);
+}
+
+/*
+       Non-static send methods
+*/
+
 void Server::SendObjectData(float dtime)
 {
        DSTACK(__FUNCTION_NAME);
@@ -3082,51 +3193,351 @@ void Server::SendInventory(u16 peer_id)
        assert(player);
 
        /*
-               Calculate crafting stuff
+               Serialize it
        */
-       if(g_settings.getBool("creative_mode") == false)
+
+       std::ostringstream os;
+       //os.imbue(std::locale("C"));
+
+       player->inventory.serialize(os);
+
+       std::string s = os.str();
+       
+       SharedBuffer<u8> data(s.size()+2);
+       writeU16(&data[0], TOCLIENT_INVENTORY);
+       memcpy(&data[2], s.c_str(), s.size());
+       
+       // Send as reliable
+       m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
+{
+       DSTACK(__FUNCTION_NAME);
+       
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[12];
+       
+       // Write command
+       writeU16(buf, TOCLIENT_CHAT_MESSAGE);
+       os.write((char*)buf, 2);
+       
+       // Write length
+       writeU16(buf, message.size());
+       os.write((char*)buf, 2);
+       
+       // Write string
+       for(u32 i=0; i<message.size(); i++)
        {
-               InventoryList *clist = player->inventory.getList("craft");
-               InventoryList *rlist = player->inventory.getList("craftresult");
+               u16 w = message[i];
+               writeU16(buf, w);
+               os.write((char*)buf, 2);
+       }
+       
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       m_con.Send(peer_id, 0, data, true);
+}
 
-               if(rlist->getUsedSlots() == 0)
-                       player->craftresult_is_preview = true;
+void Server::BroadcastChatMessage(const std::wstring &message)
+{
+       for(core::map<u16, RemoteClient*>::Iterator
+               i = m_clients.getIterator();
+               i.atEnd() == false; i++)
+       {
+               // Get client and check that it is valid
+               RemoteClient *client = i.getNode()->getValue();
+               assert(client->peer_id == i.getNode()->getKey());
+               if(client->serialization_version == SER_FMT_VER_INVALID)
+                       continue;
 
-               if(rlist && player->craftresult_is_preview)
-               {
-                       rlist->clearItems();
-               }
-               if(clist && rlist && player->craftresult_is_preview)
-               {
-                       InventoryItem *items[9];
-                       for(u16 i=0; i<9; i++)
-                       {
-                               items[i] = clist->getItem(i);
-                       }
-                       
-                       bool found = false;
+               SendChatMessage(client->peer_id, message);
+       }
+}
 
-                       // Wood
-                       if(!found)
+void Server::SendPlayerHP(Player *player)
+{
+       SendHP(m_con, player->peer_id, player->hp);
+}
+
+void Server::SendMovePlayer(Player *player)
+{
+       DSTACK(__FUNCTION_NAME);
+       std::ostringstream os(std::ios_base::binary);
+
+       writeU16(os, TOCLIENT_MOVE_PLAYER);
+       writeV3F1000(os, player->getPosition());
+       writeF1000(os, player->getPitch());
+       writeF1000(os, player->getYaw());
+       
+       {
+               v3f pos = player->getPosition();
+               f32 pitch = player->getPitch();
+               f32 yaw = player->getYaw();
+               dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
+                               <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
+                               <<" pitch="<<pitch
+                               <<" yaw="<<yaw
+                               <<std::endl;
+       }
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       m_con.Send(player->peer_id, 0, data, true);
+}
+
+void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
+       core::list<u16> *far_players, float far_d_nodes)
+{
+       float maxd = far_d_nodes*BS;
+       v3f p_f = intToFloat(p, BS);
+
+       // Create packet
+       u32 replysize = 8;
+       SharedBuffer<u8> reply(replysize);
+       writeU16(&reply[0], TOCLIENT_REMOVENODE);
+       writeS16(&reply[2], p.X);
+       writeS16(&reply[4], p.Y);
+       writeS16(&reply[6], p.Z);
+
+       for(core::map<u16, RemoteClient*>::Iterator
+               i = m_clients.getIterator();
+               i.atEnd() == false; i++)
+       {
+               // Get client and check that it is valid
+               RemoteClient *client = i.getNode()->getValue();
+               assert(client->peer_id == i.getNode()->getKey());
+               if(client->serialization_version == SER_FMT_VER_INVALID)
+                       continue;
+
+               // Don't send if it's the same one
+               if(client->peer_id == ignore_id)
+                       continue;
+               
+               if(far_players)
+               {
+                       // Get player
+                       Player *player = m_env.getPlayer(client->peer_id);
+                       if(player)
                        {
-                               ItemSpec specs[9];
-                               specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
-                               if(checkItemCombination(items, specs))
+                               // If player is far away, only set modified blocks not sent
+                               v3f player_pos = player->getPosition();
+                               if(player_pos.getDistanceFrom(p_f) > maxd)
                                {
-                                       rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
-                                       found = true;
+                                       far_players->push_back(client->peer_id);
+                                       continue;
                                }
                        }
+               }
 
-                       // Stick
-                       if(!found)
+               // Send as reliable
+               m_con.Send(client->peer_id, 0, reply, true);
+       }
+}
+
+void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
+               core::list<u16> *far_players, float far_d_nodes)
+{
+       float maxd = far_d_nodes*BS;
+       v3f p_f = intToFloat(p, BS);
+
+       for(core::map<u16, RemoteClient*>::Iterator
+               i = m_clients.getIterator();
+               i.atEnd() == false; i++)
+       {
+               // Get client and check that it is valid
+               RemoteClient *client = i.getNode()->getValue();
+               assert(client->peer_id == i.getNode()->getKey());
+               if(client->serialization_version == SER_FMT_VER_INVALID)
+                       continue;
+
+               // Don't send if it's the same one
+               if(client->peer_id == ignore_id)
+                       continue;
+
+               if(far_players)
+               {
+                       // Get player
+                       Player *player = m_env.getPlayer(client->peer_id);
+                       if(player)
                        {
-                               ItemSpec specs[9];
-                               specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-                               if(checkItemCombination(items, specs))
+                               // If player is far away, only set modified blocks not sent
+                               v3f player_pos = player->getPosition();
+                               if(player_pos.getDistanceFrom(p_f) > maxd)
                                {
-                                       rlist->addItem(new CraftItem("Stick", 4));
-                                       found = true;
+                                       far_players->push_back(client->peer_id);
+                                       continue;
+                               }
+                       }
+               }
+
+               // Create packet
+               u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
+               SharedBuffer<u8> reply(replysize);
+               writeU16(&reply[0], TOCLIENT_ADDNODE);
+               writeS16(&reply[2], p.X);
+               writeS16(&reply[4], p.Y);
+               writeS16(&reply[6], p.Z);
+               n.serialize(&reply[8], client->serialization_version);
+
+               // Send as reliable
+               m_con.Send(client->peer_id, 0, reply, true);
+       }
+}
+
+void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
+{
+       DSTACK(__FUNCTION_NAME);
+       /*
+               Create a packet with the block in the right format
+       */
+       
+       std::ostringstream os(std::ios_base::binary);
+       block->serialize(os, ver);
+       std::string s = os.str();
+       SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
+
+       u32 replysize = 8 + blockdata.getSize();
+       SharedBuffer<u8> reply(replysize);
+       v3s16 p = block->getPos();
+       writeU16(&reply[0], TOCLIENT_BLOCKDATA);
+       writeS16(&reply[2], p.X);
+       writeS16(&reply[4], p.Y);
+       writeS16(&reply[6], p.Z);
+       memcpy(&reply[8], *blockdata, blockdata.getSize());
+
+       /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
+                       <<":  \tpacket size: "<<replysize<<std::endl;*/
+       
+       /*
+               Send packet
+       */
+       m_con.Send(peer_id, 1, reply, true);
+}
+
+void Server::SendBlocks(float dtime)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       JMutexAutoLock envlock(m_env_mutex);
+       JMutexAutoLock conlock(m_con_mutex);
+
+       //TimeTaker timer("Server::SendBlocks");
+
+       core::array<PrioritySortedBlockTransfer> queue;
+
+       s32 total_sending = 0;
+
+       for(core::map<u16, RemoteClient*>::Iterator
+               i = m_clients.getIterator();
+               i.atEnd() == false; i++)
+       {
+               RemoteClient *client = i.getNode()->getValue();
+               assert(client->peer_id == i.getNode()->getKey());
+
+               total_sending += client->SendingCount();
+               
+               if(client->serialization_version == SER_FMT_VER_INVALID)
+                       continue;
+               
+               client->GetNextBlocks(this, dtime, queue);
+       }
+
+       // Sort.
+       // Lowest priority number comes first.
+       // Lowest is most important.
+       queue.sort();
+
+       for(u32 i=0; i<queue.size(); i++)
+       {
+               //TODO: Calculate limit dynamically
+               if(total_sending >= g_settings.getS32
+                               ("max_simultaneous_block_sends_server_total"))
+                       break;
+               
+               PrioritySortedBlockTransfer q = queue[i];
+
+               MapBlock *block = NULL;
+               try
+               {
+                       block = m_env.getMap().getBlockNoCreate(q.pos);
+               }
+               catch(InvalidPositionException &e)
+               {
+                       continue;
+               }
+
+               RemoteClient *client = getClient(q.peer_id);
+
+               SendBlockNoLock(q.peer_id, block, client->serialization_version);
+
+               client->SentBlock(q.pos);
+
+               total_sending++;
+       }
+}
+
+/*
+       Something random
+*/
+
+void Server::UpdateCrafting(u16 peer_id)
+{
+       DSTACK(__FUNCTION_NAME);
+       
+       Player* player = m_env.getPlayer(peer_id);
+       assert(player);
+
+       /*
+               Calculate crafting stuff
+       */
+       if(g_settings.getBool("creative_mode") == false)
+       {
+               InventoryList *clist = player->inventory.getList("craft");
+               InventoryList *rlist = player->inventory.getList("craftresult");
+
+               if(rlist->getUsedSlots() == 0)
+                       player->craftresult_is_preview = true;
+
+               if(rlist && player->craftresult_is_preview)
+               {
+                       rlist->clearItems();
+               }
+               if(clist && rlist && player->craftresult_is_preview)
+               {
+                       InventoryItem *items[9];
+                       for(u16 i=0; i<9; i++)
+                       {
+                               items[i] = clist->getItem(i);
+                       }
+                       
+                       bool found = false;
+
+                       // Wood
+                       if(!found)
+                       {
+                               ItemSpec specs[9];
+                               specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
+                               if(checkItemCombination(items, specs))
+                               {
+                                       rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
+                                       found = true;
+                               }
+                       }
+
+                       // Stick
+                       if(!found)
+                       {
+                               ItemSpec specs[9];
+                               specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+                               if(checkItemCombination(items, specs))
+                               {
+                                       rlist->addItem(new CraftItem("Stick", 4));
+                                       found = true;
                                }
                        }
 
@@ -3226,7 +3637,7 @@ void Server::SendInventory(u16 peer_id)
                                }
                        }
 
-                       // Wooden showel
+                       // Wooden shovel
                        if(!found)
                        {
                                ItemSpec specs[9];
@@ -3240,7 +3651,7 @@ void Server::SendInventory(u16 peer_id)
                                }
                        }
 
-                       // Stone showel
+                       // Stone shovel
                        if(!found)
                        {
                                ItemSpec specs[9];
@@ -3254,7 +3665,7 @@ void Server::SendInventory(u16 peer_id)
                                }
                        }
 
-                       // Steel showel
+                       // Steel shovel
                        if(!found)
                        {
                                ItemSpec specs[9];
@@ -3316,6 +3727,48 @@ void Server::SendInventory(u16 peer_id)
                                }
                        }
 
+                       // Wooden sword
+                       if(!found)
+                       {
+                               ItemSpec specs[9];
+                               specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+                               specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+                               specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+                               if(checkItemCombination(items, specs))
+                               {
+                                       rlist->addItem(new ToolItem("WSword", 0));
+                                       found = true;
+                               }
+                       }
+
+                       // Stone sword
+                       if(!found)
+                       {
+                               ItemSpec specs[9];
+                               specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+                               specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+                               specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+                               if(checkItemCombination(items, specs))
+                               {
+                                       rlist->addItem(new ToolItem("STSword", 0));
+                                       found = true;
+                               }
+                       }
+
+                       // Steel sword
+                       if(!found)
+                       {
+                               ItemSpec specs[9];
+                               specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+                               specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+                               specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+                               if(checkItemCombination(items, specs))
+                               {
+                                       rlist->addItem(new ToolItem("SteelSword", 0));
+                                       found = true;
+                               }
+                       }
+
                        // Chest
                        if(!found)
                        {
@@ -3376,264 +3829,8 @@ void Server::SendInventory(u16 peer_id)
                }
        
        } // if creative_mode == false
-
-       /*
-               Serialize it
-       */
-
-       std::ostringstream os;
-       //os.imbue(std::locale("C"));
-
-       player->inventory.serialize(os);
-
-       std::string s = os.str();
-       
-       SharedBuffer<u8> data(s.size()+2);
-       writeU16(&data[0], TOCLIENT_INVENTORY);
-       memcpy(&data[2], s.c_str(), s.size());
-       
-       // Send as reliable
-       m_con.Send(peer_id, 0, data, true);
-}
-
-void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
-{
-       DSTACK(__FUNCTION_NAME);
-       
-       std::ostringstream os(std::ios_base::binary);
-       u8 buf[12];
-       
-       // Write command
-       writeU16(buf, TOCLIENT_CHAT_MESSAGE);
-       os.write((char*)buf, 2);
-       
-       // Write length
-       writeU16(buf, message.size());
-       os.write((char*)buf, 2);
-       
-       // Write string
-       for(u32 i=0; i<message.size(); i++)
-       {
-               u16 w = message[i];
-               writeU16(buf, w);
-               os.write((char*)buf, 2);
-       }
-       
-       // Make data buffer
-       std::string s = os.str();
-       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
-       // Send as reliable
-       m_con.Send(peer_id, 0, data, true);
 }
 
-void Server::BroadcastChatMessage(const std::wstring &message)
-{
-       for(core::map<u16, RemoteClient*>::Iterator
-               i = m_clients.getIterator();
-               i.atEnd() == false; i++)
-       {
-               // Get client and check that it is valid
-               RemoteClient *client = i.getNode()->getValue();
-               assert(client->peer_id == i.getNode()->getKey());
-               if(client->serialization_version == SER_FMT_VER_INVALID)
-                       continue;
-
-               SendChatMessage(client->peer_id, message);
-       }
-}
-
-void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
-       core::list<u16> *far_players, float far_d_nodes)
-{
-       float maxd = far_d_nodes*BS;
-       v3f p_f = intToFloat(p, BS);
-
-       // Create packet
-       u32 replysize = 8;
-       SharedBuffer<u8> reply(replysize);
-       writeU16(&reply[0], TOCLIENT_REMOVENODE);
-       writeS16(&reply[2], p.X);
-       writeS16(&reply[4], p.Y);
-       writeS16(&reply[6], p.Z);
-
-       for(core::map<u16, RemoteClient*>::Iterator
-               i = m_clients.getIterator();
-               i.atEnd() == false; i++)
-       {
-               // Get client and check that it is valid
-               RemoteClient *client = i.getNode()->getValue();
-               assert(client->peer_id == i.getNode()->getKey());
-               if(client->serialization_version == SER_FMT_VER_INVALID)
-                       continue;
-
-               // Don't send if it's the same one
-               if(client->peer_id == ignore_id)
-                       continue;
-               
-               if(far_players)
-               {
-                       // Get player
-                       Player *player = m_env.getPlayer(client->peer_id);
-                       if(player)
-                       {
-                               // If player is far away, only set modified blocks not sent
-                               v3f player_pos = player->getPosition();
-                               if(player_pos.getDistanceFrom(p_f) > maxd)
-                               {
-                                       far_players->push_back(client->peer_id);
-                                       continue;
-                               }
-                       }
-               }
-
-               // Send as reliable
-               m_con.Send(client->peer_id, 0, reply, true);
-       }
-}
-
-void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
-               core::list<u16> *far_players, float far_d_nodes)
-{
-       float maxd = far_d_nodes*BS;
-       v3f p_f = intToFloat(p, BS);
-
-       for(core::map<u16, RemoteClient*>::Iterator
-               i = m_clients.getIterator();
-               i.atEnd() == false; i++)
-       {
-               // Get client and check that it is valid
-               RemoteClient *client = i.getNode()->getValue();
-               assert(client->peer_id == i.getNode()->getKey());
-               if(client->serialization_version == SER_FMT_VER_INVALID)
-                       continue;
-
-               // Don't send if it's the same one
-               if(client->peer_id == ignore_id)
-                       continue;
-
-               if(far_players)
-               {
-                       // Get player
-                       Player *player = m_env.getPlayer(client->peer_id);
-                       if(player)
-                       {
-                               // If player is far away, only set modified blocks not sent
-                               v3f player_pos = player->getPosition();
-                               if(player_pos.getDistanceFrom(p_f) > maxd)
-                               {
-                                       far_players->push_back(client->peer_id);
-                                       continue;
-                               }
-                       }
-               }
-
-               // Create packet
-               u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
-               SharedBuffer<u8> reply(replysize);
-               writeU16(&reply[0], TOCLIENT_ADDNODE);
-               writeS16(&reply[2], p.X);
-               writeS16(&reply[4], p.Y);
-               writeS16(&reply[6], p.Z);
-               n.serialize(&reply[8], client->serialization_version);
-
-               // Send as reliable
-               m_con.Send(client->peer_id, 0, reply, true);
-       }
-}
-
-void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
-{
-       DSTACK(__FUNCTION_NAME);
-       /*
-               Create a packet with the block in the right format
-       */
-       
-       std::ostringstream os(std::ios_base::binary);
-       block->serialize(os, ver);
-       std::string s = os.str();
-       SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
-
-       u32 replysize = 8 + blockdata.getSize();
-       SharedBuffer<u8> reply(replysize);
-       v3s16 p = block->getPos();
-       writeU16(&reply[0], TOCLIENT_BLOCKDATA);
-       writeS16(&reply[2], p.X);
-       writeS16(&reply[4], p.Y);
-       writeS16(&reply[6], p.Z);
-       memcpy(&reply[8], *blockdata, blockdata.getSize());
-
-       /*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                       <<":  \tpacket size: "<<replysize<<std::endl;*/
-       
-       /*
-               Send packet
-       */
-       m_con.Send(peer_id, 1, reply, true);
-}
-
-void Server::SendBlocks(float dtime)
-{
-       DSTACK(__FUNCTION_NAME);
-
-       JMutexAutoLock envlock(m_env_mutex);
-       JMutexAutoLock conlock(m_con_mutex);
-
-       //TimeTaker timer("Server::SendBlocks");
-
-       core::array<PrioritySortedBlockTransfer> queue;
-
-       s32 total_sending = 0;
-
-       for(core::map<u16, RemoteClient*>::Iterator
-               i = m_clients.getIterator();
-               i.atEnd() == false; i++)
-       {
-               RemoteClient *client = i.getNode()->getValue();
-               assert(client->peer_id == i.getNode()->getKey());
-
-               total_sending += client->SendingCount();
-               
-               if(client->serialization_version == SER_FMT_VER_INVALID)
-                       continue;
-               
-               client->GetNextBlocks(this, dtime, queue);
-       }
-
-       // Sort.
-       // Lowest priority number comes first.
-       // Lowest is most important.
-       queue.sort();
-
-       for(u32 i=0; i<queue.size(); i++)
-       {
-               //TODO: Calculate limit dynamically
-               if(total_sending >= g_settings.getS32
-                               ("max_simultaneous_block_sends_server_total"))
-                       break;
-               
-               PrioritySortedBlockTransfer q = queue[i];
-
-               MapBlock *block = NULL;
-               try
-               {
-                       block = m_env.getMap().getBlockNoCreate(q.pos);
-               }
-               catch(InvalidPositionException &e)
-               {
-                       continue;
-               }
-
-               RemoteClient *client = getClient(q.peer_id);
-
-               SendBlockNoLock(q.peer_id, block, client->serialization_version);
-
-               client->SentBlock(q.pos);
-
-               total_sending++;
-       }
-}
-
-
 RemoteClient* Server::getClient(u16 peer_id)
 {
        DSTACK(__FUNCTION_NAME);
@@ -3682,14 +3879,24 @@ void setCreativeInventory(Player *player)
 {
        player->resetInventory();
        
-       // Give some good picks
+       // Give some good tools
        {
-               InventoryItem *item = new ToolItem("STPick", 0);
+               InventoryItem *item = new ToolItem("MesePick", 0);
                void* r = player->inventory.addItem("main", item);
                assert(r == NULL);
        }
        {
-               InventoryItem *item = new ToolItem("MesePick", 0);
+               InventoryItem *item = new ToolItem("SteelPick", 0);
+               void* r = player->inventory.addItem("main", item);
+               assert(r == NULL);
+       }
+       {
+               InventoryItem *item = new ToolItem("SteelAxe", 0);
+               void* r = player->inventory.addItem("main", item);
+               assert(r == NULL);
+       }
+       {
+               InventoryItem *item = new ToolItem("SteelShovel", 0);
                void* r = player->inventory.addItem("main", item);
                assert(r == NULL);
        }
@@ -3756,6 +3963,52 @@ void setCreativeInventory(Player *player)
        }*/
 }
 
+v3f findSpawnPos(ServerMap &map)
+{
+       v2s16 nodepos;
+       s16 groundheight = 0;
+       
+       // Try to find a good place a few times
+       for(s32 i=0; i<1000; i++)
+       {
+               s32 range = 1 + i;
+               // We're going to try to throw the player to this position
+               nodepos = v2s16(-range + (myrand()%(range*2)),
+                               -range + (myrand()%(range*2)));
+               v2s16 sectorpos = getNodeSectorPos(nodepos);
+               // Get sector (NOTE: Don't get because it's slow)
+               //m_env.getMap().emergeSector(sectorpos);
+               // Get ground height at point (fallbacks to heightmap function)
+               groundheight = map.findGroundLevel(nodepos);
+               // Don't go underwater
+               if(groundheight < WATER_LEVEL)
+               {
+                       //dstream<<"-> Underwater"<<std::endl;
+                       continue;
+               }
+               // Don't go to high places
+               if(groundheight > WATER_LEVEL + 4)
+               {
+                       //dstream<<"-> Underwater"<<std::endl;
+                       continue;
+               }
+
+               // Found a good place
+               //dstream<<"Searched through "<<i<<" places."<<std::endl;
+               break;
+       }
+       
+       // If no suitable place was not found, go above water at least.
+       if(groundheight < WATER_LEVEL)
+               groundheight = WATER_LEVEL;
+
+       return intToFloat(v3s16(
+                       nodepos.X,
+                       groundheight + 2,
+                       nodepos.Y
+                       ), BS);
+}
+
 Player *Server::emergePlayer(const char *name, const char *password,
                u16 peer_id)
 {
@@ -3811,58 +4064,9 @@ Player *Server::emergePlayer(const char *name, const char *password,
                dstream<<"Server: Finding spawn place for player \""
                                <<player->getName()<<"\""<<std::endl;
 
-               v2s16 nodepos;
-#if 0
-               player->setPosition(intToFloat(v3s16(
-                               0,
-                               45, //64,
-                               0
-               ), BS));
-#endif
-#if 1
-               s16 groundheight = 0;
-#if 1
-               // Try to find a good place a few times
-               for(s32 i=0; i<1000; i++)
-               {
-                       s32 range = 1 + i;
-                       // We're going to try to throw the player to this position
-                       nodepos = v2s16(-range + (myrand()%(range*2)),
-                                       -range + (myrand()%(range*2)));
-                       v2s16 sectorpos = getNodeSectorPos(nodepos);
-                       // Get sector (NOTE: Don't get because it's slow)
-                       //m_env.getMap().emergeSector(sectorpos);
-                       // Get ground height at point (fallbacks to heightmap function)
-                       groundheight = m_env.getServerMap().findGroundLevel(nodepos);
-                       // Don't go underwater
-                       if(groundheight < WATER_LEVEL)
-                       {
-                               //dstream<<"-> Underwater"<<std::endl;
-                               continue;
-                       }
-                       // Don't go to high places
-                       if(groundheight > WATER_LEVEL + 4)
-                       {
-                               //dstream<<"-> Underwater"<<std::endl;
-                               continue;
-                       }
+               v3f pos = findSpawnPos(m_env.getServerMap());
 
-                       // Found a good place
-                       dstream<<"Searched through "<<i<<" places."<<std::endl;
-                       break;
-               }
-#endif
-               
-               // If no suitable place was not found, go above water at least.
-               if(groundheight < WATER_LEVEL)
-                       groundheight = WATER_LEVEL;
-
-               player->setPosition(intToFloat(v3s16(
-                               nodepos.X,
-                               groundheight + 5, // Accomodate mud
-                               nodepos.Y
-               ), BS));
-#endif
+               player->setPosition(pos);
 
                /*
                        Add player to environment
index 9059e91b8791dcfb1dc8ac3397b3cb2649f6ebdc..cba5fc2ce1aea7dbfc38cec1d051f8f9338857e7 100644 (file)
@@ -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);
index 5d391dbcf359d6b64d3683f26f6bf6a3b71f6248..30234f7e98920caa5e047556ae3afe6852a102e2 100644 (file)
@@ -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;
+}
+
 
index 2889d0c3940e6668fcb809070736f28382698c0a..71199475e4936ca28a2ae11a71b75cfa8a0cfd8d 100644 (file)
@@ -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
 
index c7bffcdf3813a85564b2b1789eca66908e3d54f9..07ef772eff7755c2b74de152bea0091520b1d30a 100644 (file)
@@ -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;
index 0b59ce6fdae6d8a5905c8c4a09cd914727d36e7b..c6bb3f87905304266659db5d15a3545b07f0ed0a 100644 (file)
@@ -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);
 }