diff options
-rw-r--r-- | src/client.cpp | 7 | ||||
-rw-r--r-- | src/connection.cpp | 44 | ||||
-rw-r--r-- | src/connection.h | 14 | ||||
-rw-r--r-- | src/guiInventoryMenu.cpp | 16 | ||||
-rw-r--r-- | src/inventory.cpp | 209 | ||||
-rw-r--r-- | src/inventory.h | 196 | ||||
-rw-r--r-- | src/main.cpp | 10 | ||||
-rw-r--r-- | src/server.cpp | 413 | ||||
-rw-r--r-- | src/server.h | 22 |
9 files changed, 688 insertions, 243 deletions
diff --git a/src/client.cpp b/src/client.cpp index f9cccd855..b0750cae6 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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; diff --git a/src/connection.cpp b/src/connection.cpp index e0a201773..0bc8492e6 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -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(); diff --git a/src/connection.h b/src/connection.h index 82cf9d38e..ad45278ba 100644 --- a/src/connection.h +++ b/src/connection.h @@ -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; } diff --git a/src/guiInventoryMenu.cpp b/src/guiInventoryMenu.cpp index bba23e719..a1f7d02d0 100644 --- a/src/guiInventoryMenu.cpp +++ b/src/guiInventoryMenu.cpp @@ -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 { diff --git a/src/inventory.cpp b/src/inventory.cpp index 332f9d999..a2aba311b 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -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 diff --git a/src/inventory.h b/src/inventory.h index fd2cd8778..13bd27d8b 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -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; diff --git a/src/main.cpp b/src/main.cpp index df335ad39..1a9379e41 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1513,6 +1513,10 @@ int main(int argc, char *argv[]) // Test the text input system
/*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,
NULL))->drop();*/
+
+ // Launch pause menu
+ (new GUIPauseMenu(guienv, guiroot, -1, g_device,
+ &g_active_menu_count))->drop();
// First line of debug text
gui::IGUIStaticText *guitext = guienv->addStaticText(
@@ -2164,9 +2168,11 @@ int main(int argc, char *argv[]) }
// We want a slight delay to very little
// time consuming nodes
- if(nodig_delay_counter < 0.15)
+ //float mindelay = 0.15;
+ float mindelay = 0.20;
+ if(nodig_delay_counter < mindelay)
{
- nodig_delay_counter = 0.15;
+ nodig_delay_counter = mindelay;
}
}
diff --git a/src/server.cpp b/src/server.cpp index 35f1f8a27..c0af61b98 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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 { @@ -2521,14 +2500,19 @@ 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); + } +} diff --git a/src/server.h b/src/server.h index f1baaf240..cd6f78c62 100644 --- a/src/server.h +++ b/src/server.h @@ -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; }; |