disconnect method to connection to be used instead of just timing out
authorPerttu Ahola <celeron55@gmail.com>
Fri, 24 Dec 2010 15:08:50 +0000 (17:08 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Fri, 24 Dec 2010 15:08:50 +0000 (17:08 +0200)
src/client.cpp
src/connection.cpp
src/connection.h
src/guiInventoryMenu.cpp
src/inventory.cpp
src/inventory.h
src/main.cpp
src/server.cpp
src/server.h

index f9cccd855a54a6882d7bce432bfaaa201057d59d..b0750cae6ede2d24067e80f5eadefa27375d2790 100644 (file)
@@ -117,6 +117,11 @@ Client::Client(
 
 Client::~Client()
 {
+       {
+               JMutexAutoLock conlock(m_con_mutex);
+               m_con.Disconnect();
+       }
+
        m_thread.setRun(false);
        while(m_thread.IsRunning())
                sleep_ms(100);
@@ -601,7 +606,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                
                addNode(p, n);
        }
-       if(command == TOCLIENT_PLAYERPOS)
+       else if(command == TOCLIENT_PLAYERPOS)
        {
                dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
                                <<std::endl;
index e0a201773da944849f1f4e72a034660353430633..0bc8492e6d482b34616bce20ed2e0aeba31b92ab 100644 (file)
@@ -542,6 +542,23 @@ void Connection::Connect(Address address)
        //m_waiting_new_peer_id = true;
 }
 
+void Connection::Disconnect()
+{
+       // Create and send DISCO packet
+       SharedBuffer<u8> data(2);
+       writeU8(&data[0], TYPE_CONTROL);
+       writeU8(&data[1], CONTROLTYPE_DISCO);
+       
+       // Send to all
+       core::map<u16, Peer*>::Iterator j;
+       j = m_peers.getIterator();
+       for(; j.atEnd() == false; j++)
+       {
+               Peer *peer = j.getNode()->getValue();
+               SendAsPacket(peer->id, 0, data, false);
+       }
+}
+
 bool Connection::Connected()
 {
        if(m_peers.size() != 1)
@@ -645,7 +662,22 @@ SharedBuffer<u8> Channel::ProcessPacket(
                        // the timeout counter
                        con->PrintInfo();
                        dout_con<<"PING"<<std::endl;
-                       throw ProcessedSilentlyException("Got a SET_PEER_ID");
+                       throw ProcessedSilentlyException("Got a PING");
+               }
+               else if(controltype == CONTROLTYPE_DISCO)
+               {
+                       // Just ignore it, the incoming data already reset
+                       // the timeout counter
+                       con->PrintInfo();
+                       dout_con<<"DISCO: Removing peer "<<(peer_id)<<std::endl;
+                       
+                       if(con->deletePeer(peer_id) == false)
+                       {
+                               con->PrintInfo(derr_con);
+                               derr_con<<"DISCO: Peer not found"<<std::endl;
+                       }
+
+                       throw ProcessedSilentlyException("Got a DISCO");
                }
                else{
                        con->PrintInfo(derr_con);
@@ -1323,6 +1355,16 @@ core::list<Peer*> Connection::GetPeers()
        return list;
 }
 
+bool Connection::deletePeer(u16 peer_id)
+{
+       if(m_peers.find(peer_id) == NULL)
+               return false;
+       m_peerhandler->deletingPeer(m_peers[peer_id], true);
+       delete m_peers[peer_id];
+       m_peers.remove(peer_id);
+       return true;
+}
+
 void Connection::PrintInfo(std::ostream &out)
 {
        out<<m_socket.GetHandle();
index 82cf9d38e5d61a59d6e0070279c28b1d007526de..ad45278ba26c72dbfad52c8825d51aac59f6eaf2 100644 (file)
@@ -226,12 +226,15 @@ controltype and data description:
        CONTROLTYPE_SET_PEER_ID
                [2] u16 peer_id_new
        CONTROLTYPE_PING
-       - This can be sent in a reliable packet to get a reply
+       - There is no actual reply, but this can be sent in a reliable
+         packet to get a reply
+       CONTROLTYPE_DISCO
 */
 #define TYPE_CONTROL 0
 #define CONTROLTYPE_ACK 0
 #define CONTROLTYPE_SET_PEER_ID 1
 #define CONTROLTYPE_PING 2
+#define CONTROLTYPE_DISCO 3
 /*
 ORIGINAL: This is a plain packet with no control and no error
 checking at all.
@@ -442,12 +445,15 @@ public:
        void Connect(Address address);
        bool Connected();
 
+       void Disconnect();
+
        // Sets peer_id
        SharedBuffer<u8> GetFromBuffers(u16 &peer_id);
 
        // The peer_id of sender is stored in peer_id
        // Return value: I guess this always throws an exception or
        //               actually gets data
+       // May call PeerHandler methods
        u32 Receive(u16 &peer_id, u8 *data, u32 datasize);
        
        // These will automatically package the data as an original or split
@@ -460,12 +466,18 @@ public:
        // Sends a raw packet
        void RawSend(const BufferedPacket &packet);
        
+       // May call PeerHandler methods
        void RunTimeouts(float dtime);
+
        // Can throw a PeerNotFoundException
        Peer* GetPeer(u16 peer_id);
        // returns NULL if failed
        Peer* GetPeerNoEx(u16 peer_id);
        core::list<Peer*> GetPeers();
+       
+       // Calls PeerHandler::deletingPeer
+       // Returns false if peer was not found
+       bool deletePeer(u16 peer_id);
 
        void SetPeerID(u16 id){ m_peer_id = id; }
        u16 GetPeerID(){ return m_peer_id; }
index bba23e719abf91a6d781ad4e1064a96c9750b167..a1f7d02d003a109a583776a16765c43e54038be0 100644 (file)
@@ -228,8 +228,10 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
        }
        if(event.EventType==EET_MOUSE_INPUT_EVENT)
        {
-               if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
+               if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN
+                               || event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
                {
+                       bool right = (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN);
                        v2s32 p(event.MouseInput.X, event.MouseInput.Y);
                        //dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
                        ItemSpec s = getItemAtPos(p);
@@ -248,15 +250,21 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
                                                dstream<<"Queueing IACTION_MOVE"<<std::endl;
                                                IMoveAction *a =
                                                        new IMoveAction();
-                                               a->count = 1;
+                                               a->count = right ? 1 : 0;
                                                a->from_name = m_selected_item->listname;
                                                a->from_i = m_selected_item->i;
                                                a->to_name = s.listname;
                                                a->to_i = s.i;
                                                m_actions->push_back(a);
                                        }
-                                       delete m_selected_item;
-                                       m_selected_item = NULL;
+                                       bool source_empties = false;
+                                       if(list_from && list_from->getItem(m_selected_item->i)->getCount()==1)
+                                               source_empties = true;
+                                       if(right == false || source_empties)
+                                       {
+                                               delete m_selected_item;
+                                               m_selected_item = NULL;
+                                       }
                                }
                                else
                                {
index 332f9d999c0cb8b32ee00b7f3e83997a14131bc4..a2aba311b23402c344425506386078ab6b3666d0 100644 (file)
@@ -32,8 +32,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        InventoryItem
 */
 
-InventoryItem::InventoryItem()
+InventoryItem::InventoryItem(u16 count)
 {
+       m_count = count;
 }
 
 InventoryItem::~InventoryItem()
@@ -66,6 +67,14 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
                std::getline(is, inventorystring, '|');
                return new MapBlockObjectItem(inventorystring);
        }
+       else if(name == "CraftItem")
+       {
+               std::string subname;
+               std::getline(is, subname, ' ');
+               u16 count;
+               is>>count;
+               return new CraftItem(subname, count);
+       }
        else if(name == "ToolItem")
        {
                std::string toolname;
@@ -325,83 +334,93 @@ void InventoryList::deleteItem(u32 i)
                delete item;
 }
 
-bool InventoryList::addItem(InventoryItem *newitem)
+InventoryItem * InventoryList::addItem(InventoryItem *newitem)
 {
-       // If it is a MaterialItem, try to find an already existing one
-       // and just increment the counter
-       if(std::string("MaterialItem") == newitem->getName())
+       /*
+               First try to find if it could be added to some existing items
+       */
+       for(u32 i=0; i<m_items.size(); i++)
        {
-               u8 material = ((MaterialItem*)newitem)->getMaterial();
-               u8 count = ((MaterialItem*)newitem)->getCount();
-               for(u32 i=0; i<m_items.size(); i++)
-               {
-                       InventoryItem *item2 = m_items[i];
-                       if(item2 == NULL)
-                               continue;
-                       if(std::string("MaterialItem") != item2->getName())
-                               continue;
-                       // Found one. Check if it is of the right material and has
-                       // free space
-                       MaterialItem *mitem2 = (MaterialItem*)item2;
-                       if(mitem2->getMaterial() != material)
-                               continue;
-                       //TODO: Add all that can be added and add remaining part
-                       // to another place
-                       if(mitem2->freeSpace() < count)
-                               continue;
-                       // Add to the counter
-                       mitem2->add(count);
-                       // Dump the parameter
-                       delete newitem;
-                       return true;
-               }
+               // Ignore empty slots
+               if(m_items[i] == NULL)
+                       continue;
+               // Try adding
+               newitem = addItem(i, newitem);
+               if(newitem == NULL)
+                       return NULL; // All was eaten
        }
-       // Else find an empty position
+
+       /*
+               Then try to add it to empty slots
+       */
        for(u32 i=0; i<m_items.size(); i++)
        {
-               InventoryItem *item = m_items[i];
-               if(item != NULL)
+               // Ignore unempty slots
+               if(m_items[i] != NULL)
                        continue;
-               m_items[i] = newitem;
-               return true;
+               // Try adding
+               newitem = addItem(i, newitem);
+               if(newitem == NULL)
+                       return NULL; // All was eaten
        }
-       // Failed
-       return false;
+
+       // Return leftover
+       return newitem;
 }
 
-bool InventoryList::addItem(u32 i, InventoryItem *newitem)
+InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
 {
        // If it is an empty position, it's an easy job.
-       InventoryItem *item = m_items[i];
-       if(item == NULL)
+       InventoryItem *to_item = m_items[i];
+       if(to_item == NULL)
        {
                m_items[i] = newitem;
-               return true;
+               return NULL;
        }
-
-       // If it is a material item, try to 
-       if(std::string("MaterialItem") == newitem->getName())
+       
+       // If not addable, return the item
+       if(newitem->addableTo(to_item) == false)
+               return newitem;
+       
+       // If the item fits fully in the slot, add counter and delete it
+       if(newitem->getCount() <= to_item->freeSpace())
+       {
+               to_item->add(newitem->getCount());
+               delete newitem;
+               return NULL;
+       }
+       // Else the item does not fit fully. Add all that fits and return
+       // the rest.
+       else
        {
-               u8 material = ((MaterialItem*)newitem)->getMaterial();
-               u8 count = ((MaterialItem*)newitem)->getCount();
-               InventoryItem *item2 = m_items[i];
+               u16 freespace = to_item->freeSpace();
+               to_item->add(freespace);
+               newitem->remove(freespace);
+               return newitem;
+       }
+}
 
-               if(item2 != NULL
-                       && std::string("MaterialItem") == item2->getName())
-               {
-                       // Check if it is of the right material and has free space
-                       MaterialItem *mitem2 = (MaterialItem*)item2;
-                       if(mitem2->getMaterial() == material
-                                       && mitem2->freeSpace() >= count)
-                       {
-                               // Add to the counter
-                               mitem2->add(count);
-                               // Dump the parameter
-                               delete newitem;
-                               // Done
-                               return true;
-                       }
-               }
+InventoryItem * InventoryList::takeItem(u32 i, u32 count)
+{
+       if(count == 0)
+               return NULL;
+
+       InventoryItem *item = m_items[i];
+       // If it is an empty position, return NULL
+       if(item == NULL)
+               return NULL;
+       
+       if(count >= item->getCount())
+       {
+               // Get the item by swapping NULL to its place
+               return changeItem(i, NULL);
+       }
+       else
+       {
+               InventoryItem *item2 = item->clone();
+               item->remove(count);
+               item2->setCount(count);
+               return item2;
        }
        
        return false;
@@ -411,26 +430,9 @@ void InventoryList::decrementMaterials(u16 count)
 {
        for(u32 i=0; i<m_items.size(); i++)
        {
-               InventoryItem *item = m_items[i];
-               if(item == NULL)
-                       continue;
-               if(std::string("MaterialItem") == item->getName())
-               {
-                       MaterialItem *mitem = (MaterialItem*)item;
-                       if(mitem->getCount() < count)
-                       {
-                               dstream<<__FUNCTION_NAME<<": decrementMaterials():"
-                                               <<" too small material count"<<std::endl;
-                       }
-                       else if(mitem->getCount() == count)
-                       {
-                               deleteItem(i);
-                       }
-                       else
-                       {
-                               mitem->remove(1);
-                       }
-               }
+               InventoryItem *item = takeItem(i, count);
+               if(item)
+                       delete item;
        }
 }
 
@@ -607,6 +609,10 @@ void IMoveAction::apply(Inventory *inventory)
                dstream<<" list_to->getItem(to_i)="<<list_to->getItem(to_i)
                                <<std::endl;*/
        
+       /*
+               If a list doesn't exist or the source item doesn't exist
+               or the source and the destination slots are the same
+       */
        if(!list_from || !list_to || list_from->getItem(from_i) == NULL
                        || (list_from == list_to && from_i == to_i))
        {
@@ -615,18 +621,39 @@ void IMoveAction::apply(Inventory *inventory)
        }
        
        // Take item from source list
-       InventoryItem *item1 = list_from->changeItem(from_i, NULL);
+       InventoryItem *item1 = NULL;
+       if(count == 0)
+               item1 = list_from->changeItem(from_i, NULL);
+       else
+               item1 = list_from->takeItem(from_i, count);
+
        // Try to add the item to destination list
-       if(list_to->addItem(to_i, item1))
-       {
-               // Done.
+       InventoryItem *olditem = item1;
+       item1 = list_to->addItem(to_i, item1);
+
+       // If nothing is returned, the item was fully added
+       if(item1 == NULL)
+               return;
+       
+       // If olditem is returned, nothing was added.
+       bool nothing_added = (item1 == olditem);
+       
+       // If something else is returned, part of the item was left unadded.
+       // Add the other part back to the source item
+       list_from->addItem(from_i, item1);
+
+       // If olditem is returned, nothing was added.
+       // Swap the items
+       if(nothing_added)
+       {
+               // Take item from source list
+               item1 = list_from->changeItem(from_i, NULL);
+               // Adding was not possible, swap the items.
+               InventoryItem *item2 = list_to->changeItem(to_i, item1);
+               // Put item from destination list to the source list
+               list_from->changeItem(from_i, item2);
                return;
        }
-       // Adding was not possible, switch it.
-       // Switch it to the destination list
-       InventoryItem *item2 = list_to->changeItem(to_i, item1);
-       // Put item from destination list to the source list
-       list_from->changeItem(from_i, item2);
 }
        
 //END
index fd2cd87787751bd1edaf8efb894e77279d8986d4..13bd27d8bb42e6bf257b42e508c3c46ab336dbaf 100644 (file)
@@ -33,10 +33,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 // For g_materials
 #include "main.h"
 
+#define QUANTITY_ITEM_MAX_COUNT 99
+
 class InventoryItem
 {
 public:
-       InventoryItem();
+       InventoryItem(u16 count);
        virtual ~InventoryItem();
        
        static InventoryItem* deSerialize(std::istream &is);
@@ -53,18 +55,49 @@ public:
        // Shall return a text to show in the GUI
        virtual std::string getText() { return ""; }
 
-private:
-};
+       // Shall return true if the item can be add()ed to the other
+       virtual bool addableTo(InventoryItem *other)
+       {
+               return false;
+       }
+       
+       /*
+               Quantity methods
+       */
+       u16 getCount()
+       {
+               return m_count;
+       }
+       void setCount(u16 count)
+       {
+               m_count = count;
+       }
+       virtual u16 freeSpace()
+       {
+               return 0;
+       }
+       void add(u16 count)
+       {
+               assert(m_count + count <= QUANTITY_ITEM_MAX_COUNT);
+               m_count += count;
+       }
+       void remove(u16 count)
+       {
+               assert(m_count >= count);
+               m_count -= count;
+       }
 
-#define MATERIAL_ITEM_MAX_COUNT 99
+protected:
+       u16 m_count;
+};
 
 class MaterialItem : public InventoryItem
 {
 public:
-       MaterialItem(u8 content, u16 count)
+       MaterialItem(u8 content, u16 count):
+               InventoryItem(count)
        {
                m_content = content;
-               m_count = count;
        }
        /*
                Implementation interface
@@ -107,46 +140,38 @@ public:
                os<<m_count;
                return os.str();
        }
-       /*
-               Special methods
-       */
-       u8 getMaterial()
-       {
-               return m_content;
-       }
-       u16 getCount()
+
+       virtual bool addableTo(InventoryItem *other)
        {
-               return m_count;
+               if(std::string(other->getName()) != "MaterialItem")
+                       return false;
+               MaterialItem *m = (MaterialItem*)other;
+               if(m->getMaterial() != m_content)
+                       return false;
+               return true;
        }
        u16 freeSpace()
        {
-               if(m_count > MATERIAL_ITEM_MAX_COUNT)
+               if(m_count > QUANTITY_ITEM_MAX_COUNT)
                        return 0;
-               return MATERIAL_ITEM_MAX_COUNT - m_count;
-       }
-       void add(u16 count)
-       {
-               assert(m_count + count <= MATERIAL_ITEM_MAX_COUNT);
-               m_count += count;
+               return QUANTITY_ITEM_MAX_COUNT - m_count;
        }
-       void remove(u16 count)
+       /*
+               Special methods
+       */
+       u8 getMaterial()
        {
-               assert(m_count >= count);
-               m_count -= count;
+               return m_content;
        }
 private:
        u8 m_content;
-       u16 m_count;
 };
 
 class MapBlockObjectItem : public InventoryItem
 {
 public:
-       /*MapBlockObjectItem(MapBlockObject *obj)
-       {
-               m_inventorystring = obj->getInventoryString();
-       }*/
-       MapBlockObjectItem(std::string inventorystring)
+       MapBlockObjectItem(std::string inventorystring):
+               InventoryItem(1)
        {
                m_inventorystring = inventorystring;
        }
@@ -196,10 +221,90 @@ private:
        std::string m_inventorystring;
 };
 
+/*
+       An item that is used as a mid-product when crafting.
+       Subnames:
+       - Stick
+*/
+class CraftItem : public InventoryItem
+{
+public:
+       CraftItem(std::string subname, u16 count):
+               InventoryItem(count)
+       {
+               m_subname = subname;
+       }
+       /*
+               Implementation interface
+       */
+       virtual const char* getName() const
+       {
+               return "CraftItem";
+       }
+       virtual void serialize(std::ostream &os)
+       {
+               os<<getName();
+               os<<" ";
+               os<<m_subname;
+               os<<" ";
+               os<<m_count;
+       }
+       virtual InventoryItem* clone()
+       {
+               return new CraftItem(m_subname, m_count);
+       }
+#ifndef SERVER
+       video::ITexture * getImage()
+       {
+               std::string basename;
+               if(m_subname == "Stick")
+                       basename = "../data/stick.png";
+               // Default to cloud texture
+               else
+                       basename = tile_texture_path_get(TILE_CLOUD);
+               
+               // Get such a texture
+               return g_irrlicht->getTexture(basename);
+               //return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));
+       }
+#endif
+       std::string getText()
+       {
+               std::ostringstream os;
+               os<<m_count;
+               return os.str();
+       }
+       virtual bool addableTo(InventoryItem *other)
+       {
+               if(std::string(other->getName()) != "CraftItem")
+                       return false;
+               CraftItem *m = (CraftItem*)other;
+               if(m->m_subname != m_subname)
+                       return false;
+               return true;
+       }
+       u16 freeSpace()
+       {
+               if(m_count > QUANTITY_ITEM_MAX_COUNT)
+                       return 0;
+               return QUANTITY_ITEM_MAX_COUNT - m_count;
+       }
+       /*
+               Special methods
+       */
+       std::string getSubName()
+       {
+               return m_subname;
+       }
+private:
+       std::string m_subname;
+};
+
 class ToolItem : public InventoryItem
 {
 public:
-       ToolItem(std::string toolname, u16 wear)
+       ToolItem(std::string toolname, u16 wear):
+               InventoryItem(1)
        {
                m_toolname = toolname;
                m_wear = wear;
@@ -313,11 +418,20 @@ public:
        InventoryItem * changeItem(u32 i, InventoryItem *newitem);
        // Delete item
        void deleteItem(u32 i);
-       // Adds an item to a suitable place. Returns false if failed.
-       bool addItem(InventoryItem *newitem);
-       // If possible, adds item to given slot. Returns true on success.
-       // Fails when slot is populated by a different kind of item.
-       bool addItem(u32 i, InventoryItem *newitem);
+       // Adds an item to a suitable place. Returns leftover item.
+       // If all went into the list, returns NULL.
+       InventoryItem * addItem(InventoryItem *newitem);
+
+       // If possible, adds item to given slot.
+       // If cannot be added at all, returns the item back.
+       // If can be added partly, decremented item is returned back.
+       // If can be added fully, NULL is returned.
+       InventoryItem * addItem(u32 i, InventoryItem *newitem);
+
+       // Takes some items from a slot.
+       // If there are not enough, takes as many as it can.
+       // Returns NULL if couldn't take any.
+       InventoryItem * takeItem(u32 i, u32 count);
 
        // Decrements amount of every material item
        void decrementMaterials(u16 count);
@@ -347,12 +461,13 @@ public:
        InventoryList * addList(const std::string &name, u32 size);
        InventoryList * getList(const std::string &name);
        bool deleteList(const std::string &name);
-       // A shorthand for adding items
-       bool addItem(const std::string &listname, InventoryItem *newitem)
+       // A shorthand for adding items.
+       // Returns NULL if the item was fully added, leftover otherwise.
+       InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
        {
                InventoryList *list = getList(listname);
                if(list == NULL)
-                       return false;
+                       return newitem;
                return list->addItem(newitem);
        }
        
@@ -376,6 +491,7 @@ struct InventoryAction
 
 struct IMoveAction : public InventoryAction
 {
+       // count=0 means "everything"
        u16 count;
        std::string from_name;
        s16 from_i;
index df335ad39868a8215104850641262c0a658c375f..1a9379e4141692990efd638ca14df342fcb797a1 100644 (file)
@@ -1513,6 +1513,10 @@ int main(int argc, char *argv[])
        // Test the text input system\r
        /*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,\r
                        NULL))->drop();*/\r
+       \r
+       // Launch pause menu\r
+       (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
+                       &g_active_menu_count))->drop();\r
 \r
        // First line of debug text\r
        gui::IGUIStaticText *guitext = guienv->addStaticText(\r
@@ -2164,9 +2168,11 @@ int main(int argc, char *argv[])
                                                }\r
                                                // We want a slight delay to very little\r
                                                // time consuming nodes\r
-                                               if(nodig_delay_counter < 0.15)\r
+                                               //float mindelay = 0.15;\r
+                                               float mindelay = 0.20;\r
+                                               if(nodig_delay_counter < mindelay)\r
                                                {\r
-                                                       nodig_delay_counter = 0.15;\r
+                                                       nodig_delay_counter = mindelay;\r
                                                }\r
                                        }\r
 \r
index 35f1f8a2754932d562c1733828c352f1d640d255..c0af61b989b6d856728f61c9d0ca58d8eb7fde46 100644 (file)
@@ -849,40 +849,6 @@ void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
        }
 }
 
-/*void RemoteClient::BlockEmerged()
-{
-       SharedPtr<JMutexAutoLock> lock(m_num_blocks_in_emerge_queue.getLock());
-       assert(m_num_blocks_in_emerge_queue.m_value > 0);
-       m_num_blocks_in_emerge_queue.m_value--;
-}*/
-
-/*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
-{
-       JMutexAutoLock sendinglock(m_blocks_sending_mutex);
-       
-       core::list<v3s16> remove_queue;
-       for(core::map<v3s16, float>::Iterator
-                       i = m_blocks_sending.getIterator();
-                       i.atEnd()==false; i++)
-       {
-               v3s16 p = i.getNode()->getKey();
-               float t = i.getNode()->getValue();
-               t += dtime;
-               i.getNode()->setValue(t);
-
-               if(t > timeout)
-               {
-                       remove_queue.push_back(p);
-               }
-       }
-       for(core::list<v3s16>::Iterator
-                       i = remove_queue.begin();
-                       i != remove_queue.end(); i++)
-       {
-               m_blocks_sending.remove(*i);
-       }
-}*/
-
 /*
        PlayerInfo
 */
@@ -931,7 +897,8 @@ Server::Server(
        m_emergethread(this),
        m_time_of_day(8000),
        m_time_counter(0),
-       m_time_of_day_send_timer(0)
+       m_time_of_day_send_timer(0),
+       m_uptime(0)
 {
        m_flowwater_timer = 0.0;
        m_print_info_timer = 0.0;
@@ -1026,10 +993,20 @@ void Server::AsyncRunStep()
        if(dtime < 0.001)
                return;
        
+       //dstream<<"Server steps "<<dtime<<std::endl;
+       //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
+       
        {
                JMutexAutoLock lock1(m_step_dtime_mutex);
                m_step_dtime -= dtime;
        }
+
+       /*
+               Update uptime
+       */
+       {
+               m_uptime.set(m_uptime.get() + dtime);
+       }
        
        /*
                Update m_time_of_day
@@ -1070,16 +1047,18 @@ void Server::AsyncRunStep()
                }
        }
 
-       //dstream<<"Server steps "<<dtime<<std::endl;
-       
-       //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
        {
-               // Has to be locked for peerAdded/Removed
-               JMutexAutoLock lock1(m_env_mutex);
                // Process connection's timeouts
                JMutexAutoLock lock2(m_con_mutex);
                m_con.RunTimeouts(dtime);
        }
+       
+       {
+               // This has to be called so that the client list gets synced
+               // with the peer list of the connection
+               handlePeerChanges();
+       }
+
        {
                // Step environment
                // This also runs Map's timers
@@ -1355,9 +1334,14 @@ void Server::Receive()
        u32 datasize;
        try{
                {
-                       JMutexAutoLock lock(m_con_mutex);
+                       JMutexAutoLock conlock(m_con_mutex);
                        datasize = m_con.Receive(peer_id, *data, data_maxsize);
                }
+
+               // This has to be called so that the client list gets synced
+               // with the peer list of the connection
+               handlePeerChanges();
+
                ProcessData(*data, datasize, peer_id);
        }
        catch(con::InvalidIncomingDataException &e)
@@ -1499,6 +1483,36 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        m_time_of_day.get());
                        m_con.Send(peer->id, 0, data, true);
                }
+
+               // Send information about server to player in chat
+               {
+                       std::wostringstream os(std::ios_base::binary);
+                       os<<L"# Server: ";
+                       // Uptime
+                       os<<L"uptime="<<m_uptime.get();
+                       // Information about clients
+                       os<<L", clients={";
+                       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;
+                               // Get name of player
+                               std::wstring name = L"unknown";
+                               Player *player = m_env.getPlayer(client->peer_id);
+                               if(player != NULL)
+                                       name = narrow_to_wide(player->getName());
+                               // Add name to information string
+                               os<<name<<L",";
+                       }
+                       os<<L"}";
+                       // Send message
+                       SendChatMessage(peer_id, os.str());
+               }
                
                // Send information about joining in chat
                {
@@ -1722,52 +1736,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                */
                if(action == 0)
                {
-               /*
-                       NOTE: This can be used in the future to check if
-                       somebody is cheating, by checking the timing.
-               */
-
-#if 0
-                       u8 content;
-
-                       try
-                       {
-                               // Get content at position
-                               content = m_env.getMap().getNode(p_under).d;
-                               // If it's not diggable, do nothing
-                               if(content_diggable(content) == false)
-                               {
-                                       return;
-                               }
-                       }
-                       catch(InvalidPositionException &e)
-                       {
-                               derr_server<<"Server: Not starting digging: Node not found"
-                                               <<std::endl;
-                               return;
-                       }
-                       
                        /*
-                               Set stuff in RemoteClient
+                               NOTE: This can be used in the future to check if
+                               somebody is cheating, by checking the timing.
                        */
-                       RemoteClient *client = getClient(peer->id);
-                       JMutexAutoLock(client->m_dig_mutex);
-                       client->m_dig_tool_item = 0;
-                       client->m_dig_position = p_under;
-                       float dig_time = 0.5;
-                       if(content == CONTENT_STONE)
-                       {
-                               dig_time = 1.5;
-                       }
-                       else if(content == CONTENT_TORCH)
-                       {
-                               dig_time = 0.0;
-                       }
-                       client->m_dig_time_remaining = dig_time;
-                       
-                       // Reset build time counter
-                       getClient(peer->id)->m_time_from_building.set(0.0);
-#endif
                } // action == 0
 
                /*
@@ -2240,7 +2212,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        InventoryList *clist = player->inventory.getList("craft");
                                        if(clist)
                                        {
-                                               clist->decrementMaterials(ma->count);
+                                               u16 count = ma->count;
+                                               if(count == 0)
+                                                       count = 1;
+                                               clist->decrementMaterials(count);
                                        }
                                        // Do action
                                        // Feed action to player inventory
@@ -2424,8 +2399,15 @@ void Server::peerAdded(con::Peer *peer)
        dout_server<<"Server::peerAdded(): peer->id="
                        <<peer->id<<std::endl;
        
-       // Connection is already locked when this is called.
-       //JMutexAutoLock lock(m_con_mutex);
+       PeerChange c;
+       c.type = PEER_ADDED;
+       c.peer_id = peer->id;
+       c.timeout = false;
+       m_peer_change_queue.push_back(c);
+
+#if 0
+       // NOTE: Connection is already locked when this is called.
+       // NOTE: Environment is already locked when this is called.
        
        // Error check
        core::map<u16, RemoteClient*>::Node *n;
@@ -2440,9 +2422,6 @@ void Server::peerAdded(con::Peer *peer)
 
        // Create player
        {
-               // Already locked when called
-               //JMutexAutoLock envlock(m_env_mutex);
-               
                Player *player = m_env.getPlayer(peer->id);
                
                // The player shouldn't already exist
@@ -2491,8 +2470,8 @@ void Server::peerAdded(con::Peer *peer)
                        // Give a good pick
                        {
                                InventoryItem *item = new ToolItem("STPick", 32000);
-                               bool r = player->inventory.addItem("main", item);
-                               assert(r == true);
+                               void* r = player->inventory.addItem("main", item);
+                               assert(r == NULL);
                        }
                        // Give all materials
                        assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
@@ -2508,8 +2487,8 @@ void Server::peerAdded(con::Peer *peer)
                        // Sign
                        {
                                InventoryItem *item = new MapBlockObjectItem("Sign Example text");
-                               bool r = player->inventory.addItem("main", item);
-                               assert(r == true);
+                               void* r = player->inventory.addItem("main", item);
+                               assert(r == NULL);
                        }
                        /*// Rat
                        {
@@ -2520,15 +2499,20 @@ void Server::peerAdded(con::Peer *peer)
                }
                else
                {
+                       {
+                               InventoryItem *item = new CraftItem("Stick", 4);
+                               void* r = player->inventory.addItem("main", item);
+                               assert(r == NULL);
+                       }
                        {
                                InventoryItem *item = new ToolItem("WPick", 32000);
-                               bool r = player->inventory.addItem("main", item);
-                               assert(r == true);
+                               void* r = player->inventory.addItem("main", item);
+                               assert(r == NULL);
                        }
                        {
                                InventoryItem *item = new ToolItem("STPick", 32000);
-                               bool r = player->inventory.addItem("main", item);
-                               assert(r == true);
+                               void* r = player->inventory.addItem("main", item);
+                               assert(r == NULL);
                        }
                        /*// Give some lights
                        {
@@ -2551,6 +2535,7 @@ void Server::peerAdded(con::Peer *peer)
                        }*/
                }
        }
+#endif
 }
 
 void Server::deletingPeer(con::Peer *peer, bool timeout)
@@ -2559,8 +2544,18 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
        dout_server<<"Server::deletingPeer(): peer->id="
                        <<peer->id<<", timeout="<<timeout<<std::endl;
        
-       // Connection is already locked when this is called.
-       //JMutexAutoLock lock(m_con_mutex);
+       PeerChange c;
+       c.type = PEER_REMOVED;
+       c.peer_id = peer->id;
+       c.timeout = timeout;
+       m_peer_change_queue.push_back(c);
+
+#if 0
+       // NOTE: Connection is already locked when this is called.
+
+       // NOTE: Environment is already locked when this is called.
+       // NOTE: Locking environment cannot be moved here because connection
+       //       is already locked and env has to be locked before
 
        // Error check
        core::map<u16, RemoteClient*>::Node *n;
@@ -2568,10 +2563,22 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
        // The client should exist
        assert(n != NULL);
        
+       // Send information about leaving in chat
+       {
+               std::wstring name = L"unknown";
+               Player *player = m_env.getPlayer(peer->id);
+               if(player != NULL)
+                       name = narrow_to_wide(player->getName());
+               
+               std::wstring message;
+               message += L"*** ";
+               message += name;
+               message += L" left game";
+               BroadcastChatMessage(message);
+       }
+
        // Delete player
        {
-               // Already locked when called
-               //JMutexAutoLock envlock(m_env_mutex);
                m_env.removePlayer(peer->id);
        }
        
@@ -2581,6 +2588,7 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
 
        // Send player info to all clients
        SendPlayerInfos();
+#endif
 }
 
 void Server::SendObjectData(float dtime)
@@ -2848,6 +2856,205 @@ void Server::UpdateBlockWaterPressure(MapBlock *block,
        
        v.blitBack(modified_blocks);
 }
+
+void Server::handlePeerChange(PeerChange &c)
+{
+       JMutexAutoLock envlock(m_env_mutex);
+       JMutexAutoLock conlock(m_con_mutex);
        
+       if(c.type == PEER_ADDED)
+       {
+               /*
+                       Add
+               */
+
+               // Error check
+               core::map<u16, RemoteClient*>::Node *n;
+               n = m_clients.find(c.peer_id);
+               // The client shouldn't already exist
+               assert(n == NULL);
+
+               // Create client
+               RemoteClient *client = new RemoteClient();
+               client->peer_id = c.peer_id;
+               m_clients.insert(client->peer_id, client);
+
+               // Create player
+               {
+                       Player *player = m_env.getPlayer(c.peer_id);
+                       
+                       // The player shouldn't already exist
+                       assert(player == NULL);
+
+                       player = new ServerRemotePlayer();
+                       player->peer_id = c.peer_id;
+
+                       /*
+                               Set player position
+                       */
+                       
+                       // We're going to throw the player to this position
+                       //v2s16 nodepos(29990,29990);
+                       //v2s16 nodepos(9990,9990);
+                       v2s16 nodepos(0,0);
+                       v2s16 sectorpos = getNodeSectorPos(nodepos);
+                       // Get zero sector (it could have been unloaded to disk)
+                       m_env.getMap().emergeSector(sectorpos);
+                       // Get ground height at origin
+                       f32 groundheight = m_env.getMap().getGroundHeight(nodepos, true);
+                       // The sector should have been generated -> groundheight exists
+                       assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
+                       // Don't go underwater
+                       if(groundheight < WATER_LEVEL)
+                               groundheight = WATER_LEVEL;
+
+                       player->setPosition(intToFloat(v3s16(
+                                       nodepos.X,
+                                       groundheight + 1,
+                                       nodepos.Y
+                       )));
+
+                       /*
+                               Add player to environment
+                       */
+
+                       m_env.addPlayer(player);
+
+                       /*
+                               Add stuff to inventory
+                       */
+                       
+                       if(g_settings.getBool("creative_mode"))
+                       {
+                               // Give a good pick
+                               {
+                                       InventoryItem *item = new ToolItem("STPick", 32000);
+                                       void* r = player->inventory.addItem("main", item);
+                                       assert(r == NULL);
+                               }
+                               // Give all materials
+                               assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
+                               for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
+                               {
+                                       // Skip some materials
+                                       if(i == CONTENT_OCEAN)
+                                               continue;
+
+                                       InventoryItem *item = new MaterialItem(i, 1);
+                                       player->inventory.addItem("main", item);
+                               }
+                               // Sign
+                               {
+                                       InventoryItem *item = new MapBlockObjectItem("Sign Example text");
+                                       void* r = player->inventory.addItem("main", item);
+                                       assert(r == NULL);
+                               }
+                               /*// Rat
+                               {
+                                       InventoryItem *item = new MapBlockObjectItem("Rat");
+                                       bool r = player->inventory.addItem("main", item);
+                                       assert(r == true);
+                               }*/
+                       }
+                       else
+                       {
+                               {
+                                       InventoryItem *item = new CraftItem("Stick", 4);
+                                       void* r = player->inventory.addItem("main", item);
+                                       assert(r == NULL);
+                               }
+                               {
+                                       InventoryItem *item = new ToolItem("WPick", 32000);
+                                       void* r = player->inventory.addItem("main", item);
+                                       assert(r == NULL);
+                               }
+                               {
+                                       InventoryItem *item = new ToolItem("STPick", 32000);
+                                       void* r = player->inventory.addItem("main", item);
+                                       assert(r == NULL);
+                               }
+                               /*// Give some lights
+                               {
+                                       InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);
+                                       bool r = player->inventory.addItem("main", item);
+                                       assert(r == true);
+                               }
+                               // and some signs
+                               for(u16 i=0; i<4; i++)
+                               {
+                                       InventoryItem *item = new MapBlockObjectItem("Sign Example text");
+                                       bool r = player->inventory.addItem("main", item);
+                                       assert(r == true);
+                               }*/
+                               /*// Give some other stuff
+                               {
+                                       InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
+                                       bool r = player->inventory.addItem("main", item);
+                                       assert(r == true);
+                               }*/
+                       }
+               }
+
+       } // PEER_ADDED
+       else if(c.type == PEER_REMOVED)
+       {
+               /*
+                       Delete
+               */
+
+               // Error check
+               core::map<u16, RemoteClient*>::Node *n;
+               n = m_clients.find(c.peer_id);
+               // The client should exist
+               assert(n != NULL);
+               
+               // Collect information about leaving in chat
+               std::wstring message;
+               {
+                       std::wstring name = L"unknown";
+                       Player *player = m_env.getPlayer(c.peer_id);
+                       if(player != NULL)
+                               name = narrow_to_wide(player->getName());
+                       
+                       message += L"*** ";
+                       message += name;
+                       message += L" left game";
+               }
+
+               // Delete player
+               {
+                       m_env.removePlayer(c.peer_id);
+               }
+               
+               // Delete client
+               delete m_clients[c.peer_id];
+               m_clients.remove(c.peer_id);
+
+               // Send player info to all remaining clients
+               SendPlayerInfos();
+               
+               // Send leave chat message to all remaining clients
+               BroadcastChatMessage(message);
+               
+       } // PEER_REMOVED
+       else
+       {
+               assert(0);
+       }
+}
+
+void Server::handlePeerChanges()
+{
+       while(m_peer_change_queue.size() > 0)
+       {
+               PeerChange c = m_peer_change_queue.pop_front();
+
+               dout_server<<"Server: Handling peer change: "
+                               <<"id="<<c.peer_id<<", timeout="<<c.timeout
+                               <<std::endl;
+
+               handlePeerChange(c);
+       }
+}
 
 
index f1baaf24042dfe156a5d78811c94f7c6433ae420..cd6f78c628cb704678fb2f4e1fd675df5b390a55 100644 (file)
@@ -434,6 +434,11 @@ private:
        void UpdateBlockWaterPressure(MapBlock *block,
                        core::map<v3s16, MapBlock*> &modified_blocks);
        
+       // Locks environment and connection by its own
+       struct PeerChange;
+       void handlePeerChange(PeerChange &c);
+       void handlePeerChanges();
+       
        float m_flowwater_timer;
        float m_print_info_timer;
        float m_objectdata_timer;
@@ -466,6 +471,23 @@ private:
        float m_time_counter;
        float m_time_of_day_send_timer;
        
+       MutexedVariable<float> m_uptime;
+
+       enum PeerChangeType
+       {
+               PEER_ADDED,
+               PEER_REMOVED
+       };
+
+       struct PeerChange
+       {
+               PeerChangeType type;
+               u16 peer_id;
+               bool timeout;
+       };
+       
+       Queue<PeerChange> m_peer_change_queue;
+
        friend class EmergeThread;
        friend class RemoteClient;
 };