base stuff for item->object conversion
authorPerttu Ahola <celeron55@gmail.com>
Fri, 24 Dec 2010 01:08:05 +0000 (03:08 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Fri, 24 Dec 2010 01:08:05 +0000 (03:08 +0200)
data/sign.png
src/client.cpp
src/client.h
src/inventory.cpp
src/inventory.h
src/main.cpp
src/mapblockobject.cpp
src/mapblockobject.h
src/server.cpp

index fc9081adf6c0c2fb6c6c8f9575aa3201842d7301..2e0b3cbef8dfd884f9c020a4c0a65a5ef2cd1cf1 100644 (file)
Binary files a/data/sign.png and b/data/sign.png differ
index ff40f674f4aa81f16f5562474e88c6e5914b91a5..f9cccd855a54a6882d7bce432bfaaa201057d59d 100644 (file)
@@ -568,6 +568,39 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
        // making some copypasta
        {}
 
+       if(command == TOCLIENT_REMOVENODE)
+       {
+               if(datasize < 8)
+                       return;
+               v3s16 p;
+               p.X = readS16(&data[2]);
+               p.Y = readS16(&data[4]);
+               p.Z = readS16(&data[6]);
+               
+               //TimeTaker t1("TOCLIENT_REMOVENODE", g_device);
+               
+               // This will clear the cracking animation after digging
+               ((ClientMap&)m_env.getMap()).clearTempMod(p);
+
+               removeNode(p);
+       }
+       else if(command == TOCLIENT_ADDNODE)
+       {
+               if(datasize < 8 + MapNode::serializedLength(ser_version))
+                       return;
+
+               v3s16 p;
+               p.X = readS16(&data[2]);
+               p.Y = readS16(&data[4]);
+               p.Z = readS16(&data[6]);
+               
+               //TimeTaker t1("TOCLIENT_ADDNODE", g_device);
+
+               MapNode n;
+               n.deSerialize(&data[8], ser_version);
+               
+               addNode(p, n);
+       }
        if(command == TOCLIENT_PLAYERPOS)
        {
                dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
@@ -1023,7 +1056,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 /*
        Returns true if there was something in queue
 */
-bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater)
+bool Client::AsyncProcessPacket()
 {
        DSTACK(__FUNCTION_NAME);
        
@@ -1053,40 +1086,7 @@ bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater)
        
        ToClientCommand command = (ToClientCommand)readU16(&data[0]);
 
-       if(command == TOCLIENT_REMOVENODE)
-       {
-               if(datasize < 8)
-                       return true;
-               v3s16 p;
-               p.X = readS16(&data[2]);
-               p.Y = readS16(&data[4]);
-               p.Z = readS16(&data[6]);
-               
-               //TimeTaker t1("TOCLIENT_REMOVENODE", g_device);
-               
-               // This will clear the cracking animation after digging
-               ((ClientMap&)m_env.getMap()).clearTempMod(p);
-
-               removeNode(p);
-       }
-       else if(command == TOCLIENT_ADDNODE)
-       {
-               if(datasize < 8 + MapNode::serializedLength(ser_version))
-                       return true;
-
-               v3s16 p;
-               p.X = readS16(&data[2]);
-               p.Y = readS16(&data[4]);
-               p.Z = readS16(&data[6]);
-               
-               //TimeTaker t1("TOCLIENT_ADDNODE", g_device);
-
-               MapNode n;
-               n.deSerialize(&data[8], ser_version);
-               
-               addNode(p, n);
-       }
-       else if(command == TOCLIENT_BLOCKDATA)
+       if(command == TOCLIENT_BLOCKDATA)
        {
                // Ignore too small packet
                if(datasize < 8)
@@ -1226,24 +1226,11 @@ bool Client::AsyncProcessData()
 {
        for(;;)
        {
-               // We want to update the meshes as soon as a single packet has
-               // been processed
-               LazyMeshUpdater mesh_updater(&m_env);
-               bool r = AsyncProcessPacket(mesh_updater);
+               bool r = AsyncProcessPacket();
                if(r == false)
                        break;
        }
        return false;
-
-       /*LazyMeshUpdater mesh_updater(&m_env);
-       for(;;)
-       {
-               bool r = AsyncProcessPacket(mesh_updater);
-               if(r == false)
-                       break;
-       }
-       return false;*/
-
 }
 
 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
@@ -1252,42 +1239,6 @@ void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
        m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
 }
 
-#if 0
-void Client::fetchBlock(v3s16 p, u8 flags)
-{
-       if(connectedAndInitialized() == false)
-               throw ClientNotReadyException
-               ("ClientNotReadyException: connectedAndInitialized() == false");
-
-       /*dstream<<"Client::fetchBlock(): Sending GETBLOCK for ("
-                       <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-
-       JMutexAutoLock conlock(m_con_mutex);
-
-       SharedBuffer<u8> data(9);
-       writeU16(&data[0], TOSERVER_GETBLOCK);
-       writeS16(&data[2], p.X);
-       writeS16(&data[4], p.Y);
-       writeS16(&data[6], p.Z);
-       writeU8(&data[8], flags);
-       m_con.Send(PEER_ID_SERVER, 1, data, true);
-}
-
-/*
-       Calls fetchBlock() on some nearby missing blocks.
-
-       Returns when any of various network load indicators go over limit.
-
-       Does nearly the same thing as the old updateChangedVisibleArea()
-*/
-void Client::fetchBlocks()
-{
-       if(connectedAndInitialized() == false)
-               throw ClientNotReadyException
-               ("ClientNotReadyException: connectedAndInitialized() == false");
-}
-#endif
-
 bool Client::isFetchingBlocks()
 {
        JMutexAutoLock conlock(m_con_mutex);
@@ -1369,7 +1320,7 @@ void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
        }
        
        /*
-               [0] u16 command
+               [0] u16 command=TOSERVER_CLICK_OBJECT
                [2] u8 button (0=left, 1=right)
                [3] v3s16 block
                [9] s16 id
index 6fb608b84f522e45a6669d5c0adb5abb5ebb6636..b29358d93c29fc863a886b7d133447e8446e47e2 100644 (file)
@@ -101,38 +101,6 @@ struct IncomingPacket
        s32 *m_refcount;
 };
 
-// TODO: Remove this. It is not used as supposed.
-class LazyMeshUpdater
-{
-public:
-       LazyMeshUpdater(Environment *env)
-       {
-               m_env = env;
-       }
-       ~LazyMeshUpdater()
-       {
-               /*
-                       TODO: This could be optimized. It will currently
-                       double-update some blocks.
-               */
-               for(core::map<v3s16, bool>::Iterator
-                               i = m_blocks.getIterator();
-                               i.atEnd() == false; i++)
-               {
-                       v3s16 p = i.getNode()->getKey();
-                       m_env->updateMeshes(p);
-               }
-               m_blocks.clear();
-       }
-       void add(v3s16 p)
-       {
-               m_blocks.insert(p, true);
-       }
-private:
-       Environment *m_env;
-       core::map<v3s16, bool> m_blocks;
-};
-
 class Client : public con::PeerHandler
 {
 public:
@@ -175,7 +143,7 @@ public:
 
        void ProcessData(u8 *data, u32 datasize, u16 sender_peer_id);
        // Returns true if something was received
-       bool AsyncProcessPacket(LazyMeshUpdater &mesh_updater);
+       bool AsyncProcessPacket();
        bool AsyncProcessData();
        void Send(u16 channelnum, SharedBuffer<u8> data, bool reliable);
 
index 073477dde4cc9a2f08323a6f5b52baa3660b5697..332f9d999c0cb8b32ee00b7f3e83997a14131bc4 100644 (file)
@@ -66,6 +66,14 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
                std::getline(is, inventorystring, '|');
                return new MapBlockObjectItem(inventorystring);
        }
+       else if(name == "ToolItem")
+       {
+               std::string toolname;
+               std::getline(is, toolname, ' ');
+               u16 wear;
+               is>>wear;
+               return new ToolItem(toolname, wear);
+       }
        else
        {
                dstream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
@@ -126,6 +134,19 @@ MapBlockObject * MapBlockObjectItem::createObject
                RatObject *obj = new RatObject(NULL, -1, pos);
                return obj;
        }
+       else if(name == "ItemObj")
+       {
+               /*
+                       Now we are an inventory item containing the serialization
+                       string of an object that contains the serialization
+                       string of an inventory item. Fuck this.
+               */
+               //assert(0);
+               dstream<<__FUNCTION_NAME<<": WARNING: Ignoring ItemObj "
+                               <<"because an item-object should never be inside "
+                               <<"an object-item."<<std::endl;
+               return NULL;
+       }
        else
        {
                return NULL;
index ad3b297e816de7132d1188a7879003edb75cf7c9..e97db8ffbb20d0b6bb200e93f0e54f7cff7f1953 100644 (file)
@@ -196,6 +196,78 @@ private:
        std::string m_inventorystring;
 };
 
+class ToolItem : public InventoryItem
+{
+public:
+       ToolItem(std::string toolname, u16 wear)
+       {
+               m_toolname = toolname;
+               m_wear = wear;
+       }
+       /*
+               Implementation interface
+       */
+       virtual const char* getName() const
+       {
+               return "ToolItem";
+       }
+       virtual void serialize(std::ostream &os)
+       {
+               os<<getName();
+               os<<" ";
+               os<<m_toolname;
+               os<<" ";
+               os<<m_wear;
+       }
+       virtual InventoryItem* clone()
+       {
+               return new ToolItem(m_toolname, m_wear);
+       }
+#ifndef SERVER
+       video::ITexture * getImage()
+       {
+               if(m_toolname == "WPick")
+                       return g_irrlicht->getTexture("../data/tool_wpick.png");
+               if(m_toolname == "STPick")
+                       return g_irrlicht->getTexture("../data/tool_stpick.png");
+               // Default to cloud texture
+               return g_irrlicht->getTexture(tile_texture_path_get(TILE_CLOUD));
+       }
+#endif
+       std::string getText()
+       {
+               std::ostringstream os;
+               u16 f = 4;
+               u16 d = 65535/f;
+               u16 i;
+               for(i=0; i<(65535-m_wear)/d; i++)
+                       os<<'X';
+               for(; i<f; i++)
+                       os<<'-';
+               return os.str();
+               
+               /*std::ostringstream os;
+               os<<m_toolname;
+               os<<" ";
+               os<<(m_wear/655);
+               return os.str();*/
+       }
+       /*
+               Special methods
+       */
+       std::string getToolName()
+       {
+               return m_toolname;
+       }
+       u16 getWear()
+       {
+               return m_wear;
+       }
+private:
+       std::string m_toolname;
+       u16 m_wear;
+};
+
 class InventoryList
 {
 public:
index cfc47bbb279a79120e6c09362a4535378c31b878..29ff2748cb174f8b6f25770490e23f438f20c8af 100644 (file)
@@ -105,6 +105,10 @@ SUGG: Make the amount of blocks sending to client and the total
          main network eater of this system, so it is the one that has\r
          to be throttled so that RTTs stay low.\r
 \r
+SUGG: Meshes of blocks could be split into 6 meshes facing into\r
+      different directions and then only those drawn that need to be\r
+         - Also an 1-dimensional tile map would be nice probably\r
+\r
 TODO: Untie client network operations from framerate\r
       - Needs some input queues or something\r
          - Not really necessary?\r
@@ -173,7 +177,9 @@ TODO: Check if the usage of Client::isFetchingBlocks() in
 Doing now:\r
 ======================================================================\r
 \r
-TODO: Convert the text input system to use a modal menu... or something\r
+TODO: Tool items\r
+\r
+- Actually, tool items should be just a little special MapBlockItems\r
 \r
 ======================================================================\r
 \r
@@ -269,9 +275,6 @@ extern void set_default_settings();
        Random stuff\r
 */\r
 \r
-//u16 g_selected_material = 0;\r
-u16 g_selected_item = 0;\r
-\r
 IrrlichtDevice *g_device = NULL;\r
 Client *g_client = NULL;\r
 \r
@@ -292,6 +295,8 @@ Queue<InventoryAction*> inventory_action_queue;
 // This is a copy of the inventory that the client's environment has\r
 Inventory local_inventory;\r
 \r
+u16 g_selected_item = 0;\r
+\r
 /*\r
        Debug streams\r
 */\r
@@ -1833,6 +1838,10 @@ int main(int argc, char *argv[])
                MapBlockObject *selected_object = client.getSelectedObject\r
                                (d*BS, camera_position, shootline);\r
 \r
+               /*\r
+                       If it's pointing to a MapBlockObject\r
+               */\r
+\r
                if(selected_object != NULL)\r
                {\r
                        //dstream<<"Client returned selected_object != NULL"<<std::endl;\r
@@ -2041,6 +2050,8 @@ int main(int argc, char *argv[])
                        } // regular block\r
                } // for coords\r
 \r
+               static float nodig_delay_counter = 0.0;\r
+\r
                if(nodefound)\r
                {\r
                        static v3s16 nodepos_old(-32768,-32768,-32768);\r
@@ -2048,18 +2059,6 @@ int main(int argc, char *argv[])
                        static float dig_time = 0.0;\r
                        static u16 dig_index = 0;\r
 \r
-                       if(nodepos != nodepos_old)\r
-                       {\r
-                               std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
-                                               <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
-\r
-                               if(nodepos_old != v3s16(-32768,-32768,-32768))\r
-                               {\r
-                                       client.clearTempMod(nodepos_old);\r
-                                       dig_time = 0.0;\r
-                               }\r
-                       }\r
-\r
                        hilightboxes.push_back(nodefacebox);\r
                        \r
                        if(g_input->getLeftReleased())\r
@@ -2067,42 +2066,87 @@ int main(int argc, char *argv[])
                                client.clearTempMod(nodepos);\r
                                dig_time = 0.0;\r
                        }\r
-                       if(g_input->getLeftClicked() ||\r
-                                       (g_input->getLeftState() && nodepos != nodepos_old))\r
-                       {\r
-                               dstream<<DTIME<<"Started digging"<<std::endl;\r
-                               client.groundAction(0, nodepos, neighbourpos, g_selected_item);\r
-                       }\r
-                       if(g_input->getLeftClicked())\r
+                       \r
+                       if(nodig_delay_counter > 0.0)\r
                        {\r
-                               client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));\r
+                               nodig_delay_counter -= dtime;\r
                        }\r
-                       if(g_input->getLeftState())\r
+                       else\r
                        {\r
-                               MapNode n = client.getNode(nodepos);\r
+                               if(nodepos != nodepos_old)\r
+                               {\r
+                                       std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
+                                                       <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
 \r
-                               // TODO: Get this from some table that is sent by server\r
-                               float dig_time_complete = 0.5;\r
-                               if(n.d == CONTENT_STONE)\r
-                                       dig_time_complete = 1.5;\r
-                               \r
-                               dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
-                                               * dig_time/dig_time_complete);\r
+                                       if(nodepos_old != v3s16(-32768,-32768,-32768))\r
+                                       {\r
+                                               client.clearTempMod(nodepos_old);\r
+                                               dig_time = 0.0;\r
+                                       }\r
+                               }\r
 \r
-                               if(dig_index < CRACK_ANIMATION_LENGTH)\r
+                               if(g_input->getLeftClicked() ||\r
+                                               (g_input->getLeftState() && nodepos != nodepos_old))\r
                                {\r
-                                       //dstream<<"dig_index="<<dig_index<<std::endl;\r
-                                       client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
+                                       dstream<<DTIME<<"Started digging"<<std::endl;\r
+                                       client.groundAction(0, nodepos, neighbourpos, g_selected_item);\r
                                }\r
-                               else\r
+                               if(g_input->getLeftClicked())\r
                                {\r
-                                       dstream<<DTIME<<"Digging completed"<<std::endl;\r
-                                       client.groundAction(3, nodepos, neighbourpos, g_selected_item);\r
-                                       client.clearTempMod(nodepos);\r
-                                       client.removeNode(nodepos);\r
+                                       client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));\r
                                }\r
+                               if(g_input->getLeftState())\r
+                               {\r
+                                       MapNode n = client.getNode(nodepos);\r
+\r
+                                       // TODO: Get this from some table that is sent by server\r
+                                       float dig_time_complete = 0.5;\r
+                                       if(n.d == CONTENT_STONE || n.d == CONTENT_COALSTONE)\r
+                                       {\r
+                                               dig_time_complete = 10.0;\r
+\r
+                                               InventoryList *mlist = local_inventory.getList("main");\r
+                                               if(mlist != NULL)\r
+                                               {\r
+                                                       InventoryItem *item = mlist->getItem(g_selected_item);\r
+                                                       if((std::string)item->getName() == "ToolItem")\r
+                                                       {\r
+                                                               ToolItem *titem = (ToolItem*)item;\r
+                                                               if(titem->getToolName() == "WPick")\r
+                                                               {\r
+                                                                       dig_time_complete = 1.2;\r
+                                                               }\r
+                                                               else if(titem->getToolName() == "STPick")\r
+                                                               {\r
+                                                                       dig_time_complete = 0.6;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
+                                                       * dig_time/dig_time_complete);\r
 \r
-                               dig_time += dtime;\r
+                                       if(dig_index < CRACK_ANIMATION_LENGTH)\r
+                                       {\r
+                                               //dstream<<"dig_index="<<dig_index<<std::endl;\r
+                                               client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               dstream<<DTIME<<"Digging completed"<<std::endl;\r
+                                               client.groundAction(3, nodepos, neighbourpos, g_selected_item);\r
+                                               client.clearTempMod(nodepos);\r
+                                               client.removeNode(nodepos);\r
+\r
+                                               dig_time = 0;\r
+\r
+                                               nodig_delay_counter = dig_time_complete\r
+                                                               / (float)CRACK_ANIMATION_LENGTH;\r
+                                       }\r
+\r
+                                       dig_time += dtime;\r
+                               }\r
                        }\r
                        \r
                        if(g_input->getRightClicked())\r
index d5c9c997a40a832d21ed96ed8aabea64ef073c6a..653dbc332b230309883c972e8e25fcfe86ab5a83 100644 (file)
@@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapblock.h"
 // Only for ::getNodeBox, TODO: Get rid of this
 #include "map.h"
+#include "inventory.h"
+#include "irrlichtwrapper.h"
 
 /*
        MapBlockObject
@@ -293,10 +295,101 @@ void RatObject::addToScene(scene::ISceneManager *smgr)
 }
 #endif
 
+/*
+       ItemObject
+*/
 #ifndef SERVER
+void ItemObject::addToScene(scene::ISceneManager *smgr)
+{
+       if(m_node != NULL)
+               return;
+       
+       //video::IVideoDriver* driver = smgr->getVideoDriver();
+       
+       // Get image of item for showing
+       video::ITexture *texture = getItemImage();
+
+       /*
+               Create a mesh
+       */
+
+       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,-BS/2,0, 0,0,0, c, 0,1),
+               video::S3DVertex(-BS/2,-BS/2,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),*/
+               video::S3DVertex(BS/3,-BS/2,0, 0,0,0, c, 0,1),
+               video::S3DVertex(-BS/3,-BS/2,0, 0,0,0, c, 1,1),
+               video::S3DVertex(-BS/3,-BS/2+BS*2/3,0, 0,0,0, c, 1,0),
+               video::S3DVertex(BS/3,-BS/2+BS*2/3,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, texture);
+       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+       buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
+       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+       // Add to mesh
+       mesh->addMeshBuffer(buf);
+       buf->drop();
+       }
+       m_node = smgr->addMeshSceneNode(mesh, NULL);
+       // Set it to use the materials of the meshbuffers directly.
+       // This is needed for changing the texture in the future
+       ((scene::IMeshSceneNode*)m_node)->setReadOnlyMaterials(true);
+       mesh->drop();
+
+       updateSceneNode();
+}
+
+video::ITexture * ItemObject::getItemImage()
+{
+       /*
+               Create an inventory item to see what is its image
+       */
+       video::ITexture *texture = NULL;
+       InventoryItem *item = createInventoryItem();
+       if(item)
+               texture = item->getImage();
+       /*else
+               texture = g_irrlicht->getTexture("../data/cloud.png");*/
+       if(item)
+               delete item;
+       return texture;
+}
+
+#endif
+
+InventoryItem * ItemObject::createInventoryItem()
+{
+       try{
+               std::istringstream is(m_itemstring, std::ios_base::binary);
+               InventoryItem *item = InventoryItem::deSerialize(is);
+               dstream<<__FUNCTION_NAME<<": m_itemstring=\""
+                               <<m_itemstring<<"\" -> item="<<item
+                               <<std::endl;
+               return item;
+       }
+       catch(SerializationError &e)
+       {
+               dstream<<__FUNCTION_NAME<<": serialization error: "
+                               <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
+               return NULL;
+       }
+}
+
 /*
        PlayerObject
 */
+#ifndef SERVER
 void PlayerObject::addToScene(scene::ISceneManager *smgr)
 {
        if(m_node != NULL)
@@ -480,6 +573,10 @@ void MapBlockObjectList::update(std::istream &is, u8 version,
                        {
                                obj = new RatObject(m_block, id, pos);
                        }
+                       else if(type_id == MAPBLOCKOBJECT_TYPE_ITEM)
+                       {
+                               obj = new ItemObject(m_block, id, pos);
+                       }
                        else
                        {
                                // This is fatal because we cannot know the length
index a65ffd8e82b0df5a467aa1633bc8ad464c685e3e..05d5229019486b01108853712d84ccf752e0bd9f 100644 (file)
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MAPBLOCKOBJECT_TYPE_PLAYER 0
 #define MAPBLOCKOBJECT_TYPE_SIGN 2
 #define MAPBLOCKOBJECT_TYPE_RAT 3
+#define MAPBLOCKOBJECT_TYPE_ITEM 4
 // Used for handling selecting special stuff
 //#define MAPBLOCKOBJECT_TYPE_PSEUDO 1000
 
@@ -719,6 +720,182 @@ protected:
        float m_age;
 };
 
+/*
+       An object on the map that represents an inventory item
+*/
+
+class InventoryItem;
+
+class ItemObject : public MapBlockObject
+{
+public:
+       // The constructor of every MapBlockObject should be like this
+       ItemObject(MapBlock *block, s16 id, v3f pos):
+               MapBlockObject(block, id, pos),
+               m_node(NULL)
+       {
+               /*m_selection_box = new core::aabbox3d<f32>
+                               (-BS*0.4,-BS*0.5,-BS*0.4, BS*0.4,BS*0.5,BS*0.4);*/
+               m_selection_box = new core::aabbox3d<f32>
+                               (-BS/3,-BS/2,-BS/3, BS/3,-BS/2+BS*2/3,BS/3);
+               m_yaw = 0.0;
+       }
+       virtual ~ItemObject()
+       {
+               delete m_selection_box;
+       }
+       
+       /*
+               Implementation interface
+       */
+       virtual u16 getTypeId() const
+       {
+               return MAPBLOCKOBJECT_TYPE_ITEM;
+       }
+       virtual void serialize(std::ostream &os, u8 version)
+       {
+               serializeBase(os, version);
+               u8 buf[2];
+
+               // Write text length
+               writeU16(buf, m_itemstring.size());
+               os.write((char*)buf, 2);
+               
+               // Write text
+               os.write(m_itemstring.c_str(), m_itemstring.size());
+       }
+       virtual void update(std::istream &is, u8 version)
+       {
+               u8 buf[2];
+
+               // Read text length
+               is.read((char*)buf, 2);
+               u16 size = readU16(buf);
+
+               // Read text
+               std::string old_itemstring = m_itemstring;
+               m_itemstring.clear();
+               for(u16 i=0; i<size; i++)
+               {
+                       is.read((char*)buf, 1);
+                       m_itemstring += buf[0];
+               }
+               
+#ifndef SERVER
+               if(m_itemstring != old_itemstring && m_node)
+               {
+                       /*
+                               Update texture
+                       */
+                       video::ITexture *texture = getItemImage();
+                       scene::IMesh *mesh = m_node->getMesh();
+                       if(mesh->getMeshBufferCount() >= 1)
+                       {
+                               scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
+                               //dstream<<"Setting texture "<<texture<<std::endl;
+                               buf->getMaterial().setTexture(0, texture);
+                       }
+               }
+               
+               updateSceneNode();
+#endif
+       }
+
+       virtual bool serverStep(float dtime, u32 daynight_ratio)
+       {
+               return false;
+       }
+
+#ifndef SERVER
+       virtual void clientStep(float dtime)
+       {
+               m_yaw += dtime * 90;
+               if(m_yaw >= 360.)
+                       m_yaw -= 360.;
+
+               updateSceneNode();
+       }
+       
+       virtual void addToScene(scene::ISceneManager *smgr);
+       
+       virtual void removeFromScene()
+       {
+               if(m_node != NULL)
+               {
+                       m_node->remove();
+                       m_node = NULL;
+               }
+       }
+       virtual void 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();
+               
+               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;
+                       }
+               }
+       }
+#endif
+
+       virtual std::string infoText()
+       {
+               return std::string("\"") + m_itemstring + "\"";
+       }
+
+       virtual std::string getInventoryString()
+       {
+               return std::string("ItemObj ")+m_itemstring;
+       }
+
+       /*
+               Special methods
+       */
+
+       InventoryItem * createInventoryItem();
+       
+#ifndef SERVER
+       video::ITexture * getItemImage();
+
+       void updateSceneNode()
+       {
+               if(m_node != NULL)
+               {
+                       m_node->setPosition(getAbsolutePos());
+                       m_node->setRotation(v3f(0, m_yaw, 0));
+               }
+       }
+#endif
+
+       void setItemString(std::string inventorystring)
+       {
+               m_itemstring = inventorystring;
+               setBlockChanged();
+       }
+
+       std::string getItemString()
+       {
+               return m_itemstring;
+       }
+
+protected:
+       scene::IMeshSceneNode *m_node;
+       std::string m_itemstring;
+       f32 m_yaw;
+};
+
 /*
        NOTE: Not used.
 */
index d7bd226683e05df86c1f46ab7a2d524d21397f5e..db4e0422880c3e918b6d6fed79aa493b1ed416d3 100644 (file)
@@ -1635,7 +1635,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                }
                catch(InvalidPositionException &e)
                {
-                       derr_server<<"PICK_OBJECT block not found"<<std::endl;
+                       derr_server<<"CLICK_OBJECT block not found"<<std::endl;
                        return;
                }
 
@@ -1643,7 +1643,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                if(obj == NULL)
                {
-                       derr_server<<"PICK_OBJECT object not found"<<std::endl;
+                       derr_server<<"CLICK_OBJECT object not found"<<std::endl;
                        return;
                }
 
@@ -1662,10 +1662,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        dout_server<<"Player inventory has no free space"<<std::endl;
                                        return;
                                }
-                       
+                               
+                               /*
+                                       Create the inventory item
+                               */
+                               InventoryItem *item = NULL;
+                               // If it is an item-object, take the item from it
+                               if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
+                               {
+                                       item = ((ItemObject*)obj)->createInventoryItem();
+                               }
+                               // Else create an item of the object
+                               else
+                               {
+                                       item = new MapBlockObjectItem
+                                                       (obj->getInventoryString());
+                               }
+                               
                                // Add to inventory and send inventory
-                               InventoryItem *item = new MapBlockObjectItem
-                                               (obj->getInventoryString());
                                ilist->addItem(item);
                                SendInventory(player->peer_id);
                        }
@@ -2021,17 +2035,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                v.blitBack(modified_blocks);
                        }
                        /*
-                               Handle block object items
+                               Handle other items
                        */
-                       else if(std::string("MBOItem") == item->getName())
+                       else
                        {
-                               MapBlockObjectItem *oitem = (MapBlockObjectItem*)item;
-
-                               /*dout_server<<"Trying to place a MapBlockObjectItem: "
-                                               "inventorystring=\""
-                                               <<oitem->getInventoryString()
-                                               <<"\""<<std::endl;*/
-
                                v3s16 blockpos = getNodeBlockPos(p_over);
 
                                MapBlock *block = NULL;
@@ -2056,25 +2063,61 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
                                                <<std::endl;*/
 
+                               MapBlockObject *obj = NULL;
 
-                               MapBlockObject *obj = oitem->createObject
-                                               (pos, player->getYaw(), player->getPitch());
+                               /*
+                                       Handle block object items
+                               */
+                               if(std::string("MBOItem") == item->getName())
+                               {
+                                       MapBlockObjectItem *oitem = (MapBlockObjectItem*)item;
+
+                                       /*dout_server<<"Trying to place a MapBlockObjectItem: "
+                                                       "inventorystring=\""
+                                                       <<oitem->getInventoryString()
+                                                       <<"\""<<std::endl;*/
+                                                       
+                                       obj = oitem->createObject
+                                                       (pos, player->getYaw(), player->getPitch());
+                               }
+                               /*
+                                       Handle other items
+                               */
+                               else
+                               {
+                                       dout_server<<"Placing a miscellaneous item on map"
+                                                       <<std::endl;
+                                       /*
+                                               Create an ItemObject that contains the item.
+                                       */
+                                       ItemObject *iobj = new ItemObject(NULL, -1, pos);
+                                       std::ostringstream os(std::ios_base::binary);
+                                       item->serialize(os);
+                                       dout_server<<"Item string is \""<<os.str()<<"\""<<std::endl;
+                                       iobj->setItemString(os.str());
+                                       obj = iobj;
+                               }
 
                                if(obj == NULL)
-                                       derr_server<<"WARNING: oitem created NULL object"
+                               {
+                                       derr_server<<"WARNING: item resulted in NULL object, "
+                                                       <<"not placing onto map"
                                                        <<std::endl;
+                               }
+                               else
+                               {
+                                       block->addObject(obj);
 
-                               block->addObject(obj);
-
-                               //dout_server<<"Placed object"<<std::endl;
+                                       dout_server<<"Placed object"<<std::endl;
 
-                               InventoryList *ilist = player->inventory.getList("main");
-                               if(g_settings.getBool("creative_mode") == false && ilist)
-                               {
-                                       // Remove from inventory and send inventory
-                                       ilist->deleteItem(item_i);
-                                       // Send inventory
-                                       SendInventory(peer_id);
+                                       InventoryList *ilist = player->inventory.getList("main");
+                                       if(g_settings.getBool("creative_mode") == false && ilist)
+                                       {
+                                               // Remove from inventory and send inventory
+                                               ilist->deleteItem(item_i);
+                                               // Send inventory
+                                               SendInventory(peer_id);
+                                       }
                                }
                        }
 
@@ -2445,6 +2488,12 @@ void Server::peerAdded(con::Peer *peer)
                
                if(g_settings.getBool("creative_mode"))
                {
+                       // Give a good pick
+                       {
+                               InventoryItem *item = new ToolItem("STPick", 32000);
+                               bool r = player->inventory.addItem("main", item);
+                               assert(r == true);
+                       }
                        // Give all materials
                        assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
                        for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
@@ -2471,6 +2520,16 @@ void Server::peerAdded(con::Peer *peer)
                }
                else
                {
+                       {
+                               InventoryItem *item = new ToolItem("WPick", 32000);
+                               bool r = player->inventory.addItem("main", item);
+                               assert(r == true);
+                       }
+                       {
+                               InventoryItem *item = new ToolItem("STPick", 32000);
+                               bool r = player->inventory.addItem("main", item);
+                               assert(r == true);
+                       }
                        /*// Give some lights
                        {
                                InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);