+ // Only complete digging of nodes
+ if(pointed.type != POINTEDTHING_NODE)
+ return;
+
+ // Mandatory parameter; actually used for nothing
+ core::map<v3s16, MapBlock*> modified_blocks;
+
+ content_t material = CONTENT_IGNORE;
+ u8 mineral = MINERAL_NONE;
+
+ bool cannot_remove_node = !build_priv;
+
+ MapNode n(CONTENT_IGNORE);
+ try
+ {
+ n = m_env->getMap().getNode(p_under);
+ // Get mineral
+ mineral = n.getMineral(m_nodedef);
+ // Get material at position
+ material = n.getContent();
+ // If not yet cancelled
+ if(cannot_remove_node == false)
+ {
+ // If it's not diggable, do nothing
+ if(m_nodedef->get(material).diggable == false)
+ {
+ infostream<<"Server: Not finishing digging: "
+ <<"Node not diggable"
+ <<std::endl;
+ cannot_remove_node = true;
+ }
+ }
+ // If not yet cancelled
+ if(cannot_remove_node == false)
+ {
+ // Get node metadata
+ NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
+ if(meta && meta->nodeRemovalDisabled() == true)
+ {
+ infostream<<"Server: Not finishing digging: "
+ <<"Node metadata disables removal"
+ <<std::endl;
+ cannot_remove_node = true;
+ }
+ }
+ }
+ catch(InvalidPositionException &e)
+ {
+ infostream<<"Server: Not finishing digging: Node not found."
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+ cannot_remove_node = true;
+ }
+
+ /*
+ If node can't be removed, set block to be re-sent to
+ client and quit.
+ */
+ if(cannot_remove_node)
+ {
+ infostream<<"Server: Not finishing digging."<<std::endl;
+
+ // Client probably has wrong data.
+ // Set block not sent, so that client will get
+ // a valid one.
+ infostream<<"Client "<<peer_id<<" tried to dig "
+ <<"node; but node cannot be removed."
+ <<" setting MapBlock not sent."<<std::endl;
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(p_under);
+ client->SetBlockNotSent(blockpos);
+
+ return;
+ }
+
+ actionstream<<player->getName()<<" digs "<<PP(p_under)
+ <<", gets material "<<(int)material<<", mineral "
+ <<(int)mineral<<std::endl;
+
+ /*
+ Send the removal to all close-by players.
+ - If other player is close, send REMOVENODE
+ - Otherwise set blocks not sent
+ */
+ core::list<u16> far_players;
+ sendRemoveNode(p_under, peer_id, &far_players, 30);
+
+ /*
+ Update and send inventory
+ */
+
+ if(g_settings->getBool("creative_mode") == false)
+ {
+ /*
+ Wear out tool
+ */
+ InventoryList *mlist = player->inventory.getList("main");
+ if(mlist != NULL)
+ {
+ InventoryItem *item = mlist->getItem(item_i);
+ if(item && (std::string)item->getName() == "ToolItem")
+ {
+ ToolItem *titem = (ToolItem*)item;
+ std::string toolname = titem->getToolName();
+
+ // Get digging properties for material and tool
+ ToolDiggingProperties tp =
+ m_toolmgr->getDiggingProperties(toolname);
+ DiggingProperties prop =
+ getDiggingProperties(material, &tp, m_nodedef);
+
+ if(prop.diggable == false)
+ {
+ infostream<<"Server: WARNING: Player digged"
+ <<" with impossible material + tool"
+ <<" combination"<<std::endl;
+ }
+
+ bool weared_out = titem->addWear(prop.wear);
+
+ if(weared_out)
+ {
+ mlist->deleteItem(item_i);
+ }
+
+ srp->m_inventory_not_sent = true;
+ }
+ }
+
+ /*
+ Add dug item to inventory
+ */
+
+ InventoryItem *item = NULL;
+
+ if(mineral != MINERAL_NONE)
+ item = getDiggedMineralItem(mineral, this);
+
+ // If not mineral
+ if(item == NULL)
+ {
+ const std::string &dug_s = m_nodedef->get(material).dug_item;
+ if(dug_s != "")
+ {
+ std::istringstream is(dug_s, std::ios::binary);
+ item = InventoryItem::deSerialize(is, this);
+ }
+ }
+
+ if(item != NULL)
+ {
+ // Add a item to inventory
+ player->inventory.addItem("main", item);
+ srp->m_inventory_not_sent = true;
+ }
+
+ item = NULL;
+
+ if(mineral != MINERAL_NONE)
+ item = getDiggedMineralItem(mineral, this);
+
+ // If not mineral
+ if(item == NULL)
+ {
+ const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
+ s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
+ if(extra_dug_s != "" && extra_rarity != 0
+ && myrand() % extra_rarity == 0)
+ {
+ std::istringstream is(extra_dug_s, std::ios::binary);
+ item = InventoryItem::deSerialize(is, this);
+ }
+ }
+
+ if(item != NULL)
+ {
+ // Add a item to inventory
+ player->inventory.addItem("main", item);
+ srp->m_inventory_not_sent = true;
+ }
+ }
+
+ /*
+ Remove the node
+ (this takes some time so it is done after the quick stuff)
+ */
+ {
+ MapEditEventIgnorer ign(&m_ignore_map_edit_events);
+
+ m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
+ }
+ /*
+ Set blocks not sent to far players
+ */
+ for(core::list<u16>::Iterator
+ i = far_players.begin();
+ i != far_players.end(); i++)
+ {
+ u16 peer_id = *i;
+ RemoteClient *client = getClient(peer_id);
+ if(client==NULL)
+ continue;
+ client->SetBlocksNotSent(modified_blocks);
+ }