- if(datasize < 17)
- return;
- /*
- length: 17
- [0] u16 command
- [2] u8 action
- [3] v3s16 nodepos_undersurface
- [9] v3s16 nodepos_abovesurface
- [15] u16 item
- actions:
- 0: start digging
- 1: place block
- 2: stop digging (all parameters ignored)
- 3: digging completed
- */
- u8 action = readU8(&data[2]);
- v3s16 p_under;
- p_under.X = readS16(&data[3]);
- p_under.Y = readS16(&data[5]);
- p_under.Z = readS16(&data[7]);
- v3s16 p_over;
- p_over.X = readS16(&data[9]);
- p_over.Y = readS16(&data[11]);
- p_over.Z = readS16(&data[13]);
- u16 item_i = readU16(&data[15]);
-
- //TODO: Check that target is reasonably close
-
- /*
- 0: start digging
- */
- if(action == 0)
- {
- /*
- NOTE: This can be used in the future to check if
- somebody is cheating, by checking the timing.
- */
- } // action == 0
-
- /*
- 2: stop digging
- */
- else if(action == 2)
- {
-#if 0
- RemoteClient *client = getClient(peer_id);
- JMutexAutoLock digmutex(client->m_dig_mutex);
- client->m_dig_tool_item = -1;
-#endif
- }
-
- /*
- 3: Digging completed
- */
- else if(action == 3)
- {
- // 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 = false;
-
- try
- {
- MapNode n = m_env->getMap().getNode(p_under);
- // Get mineral
- mineral = n.getMineral(m_nodemgr);
- // 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_nodemgr->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_over), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_remove_node = true;
- }
-
- // Make sure the player is allowed to do it
- if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
- {
- infostream<<"Player "<<player->getName()<<" cannot remove node"
- <<" because privileges are "<<getPlayerPrivs(player)
- <<std::endl;
- 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_nodemgr);
-
- 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);
- }
- }
- }
-
- /*
- 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_nodemgr->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);
-
- // Send inventory
- UpdateCrafting(player->peer_id);
- SendInventory(player->peer_id);
- }
-
- item = NULL;
-
- if(mineral != MINERAL_NONE)
- item = getDiggedMineralItem(mineral, this);
-
- // If not mineral
- if(item == NULL)
- {
- const std::string &extra_dug_s = m_nodemgr->get(material).extra_dug_item;
- s32 extra_rarity = m_nodemgr->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);
-
- // Send inventory
- UpdateCrafting(player->peer_id);
- SendInventory(player->peer_id);
- }
- }
-
- /*
- 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);
- }
- }
-
- /*
- 1: place block
- */
- else if(action == 1)
- {
-
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist == NULL)
- return;
-
- // Get item
- InventoryItem *item = ilist->getItem(item_i);
-
- // If there is no item, it is not possible to add it anywhere
- if(item == NULL)
- return;
-
- /*
- Handle material items
- */
- if(std::string("MaterialItem") == item->getName())
- {
- try{
- // Don't add a node if this is not a free space
- MapNode n2 = m_env->getMap().getNode(p_over);
- bool no_enough_privs =
- ((getPlayerPrivs(player) & PRIV_BUILD)==0);
- if(no_enough_privs)
- infostream<<"Player "<<player->getName()<<" cannot add node"
- <<" because privileges are "<<getPlayerPrivs(player)
- <<std::endl;
-
- if(m_nodemgr->get(n2).buildable_to == false
- || no_enough_privs)
- {
- // Client probably has wrong data.
- // Set block not sent, so that client will get
- // a valid one.
- infostream<<"Client "<<peer_id<<" tried to place"
- <<" node in invalid position; setting"
- <<" MapBlock not sent."<<std::endl;
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_over);
- client->SetBlockNotSent(blockpos);
- return;
- }
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Ignoring ADDNODE: Node not found"
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
- return;
- }
-
- // Reset build time counter
- getClient(peer_id)->m_time_from_building = 0.0;
-
- // Create node data
- MaterialItem *mitem = (MaterialItem*)item;
- MapNode n;
- n.setContent(mitem->getMaterial());
-
- actionstream<<player->getName()<<" places material "
- <<(int)mitem->getMaterial()
- <<" at "<<PP(p_under)<<std::endl;
-
- // Calculate direction for wall mounted stuff
- if(m_nodemgr->get(n).wall_mounted)
- n.param2 = packDir(p_under - p_over);
-
- // Calculate the direction for furnaces and chests and stuff
- if(m_nodemgr->get(n).param_type == CPT_FACEDIR_SIMPLE)
- {
- v3f playerpos = player->getPosition();
- v3f blockpos = intToFloat(p_over, BS) - playerpos;
- blockpos = blockpos.normalize();
- n.param1 = 0;
- if (fabs(blockpos.X) > fabs(blockpos.Z)) {
- if (blockpos.X < 0)
- n.param1 = 3;
- else
- n.param1 = 1;
- } else {
- if (blockpos.Z < 0)
- n.param1 = 2;
- else
- n.param1 = 0;
- }
- }
-
- /*
- Send to all close-by players
- */
- core::list<u16> far_players;
- sendAddNode(p_over, n, 0, &far_players, 30);
-
- /*
- Handle inventory
- */
- InventoryList *ilist = player->inventory.getList("main");
- if(g_settings->getBool("creative_mode") == false && ilist)
- {
- // Remove from inventory and send inventory
- if(mitem->getCount() == 1)
- ilist->deleteItem(item_i);
- else
- mitem->remove(1);
- // Send inventory
- UpdateCrafting(peer_id);
- SendInventory(peer_id);
- }
-
- /*
- Add node.
-
- This takes some time so it is done after the quick stuff
- */
- core::map<v3s16, MapBlock*> modified_blocks;
- {
- MapEditEventIgnorer ign(&m_ignore_map_edit_events);
-
- std::string p_name = std::string(player->getName());
- m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
- }
- /*
- 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);
- }
-
- /*
- Calculate special events
- */
-
- /*if(n.d == CONTENT_MESE)
- {
- u32 count = 0;
- for(s16 z=-1; z<=1; z++)
- for(s16 y=-1; y<=1; y++)
- for(s16 x=-1; x<=1; x++)
- {
-
- }
- }*/
- }
- /*
- Place other item (not a block)
- */
- else
- {
- v3s16 blockpos = getNodeBlockPos(p_over);
-
- /*
- Check that the block is loaded so that the item
- can properly be added to the static list too
- */
- MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
- if(block==NULL)
- {
- infostream<<"Error while placing object: "
- "block not found"<<std::endl;
- return;
- }
-
- /*
- If in creative mode, item dropping is disabled unless
- player has build privileges
- */
- if(g_settings->getBool("creative_mode") &&
- (getPlayerPrivs(player) & PRIV_BUILD) == 0)
- {
- infostream<<"Not allowing player to drop item: "
- "creative mode and no build privs"<<std::endl;
- return;
- }
-
- // Calculate a position for it
- v3f pos = intToFloat(p_over, BS);
- //pos.Y -= BS*0.45;
- /*pos.Y -= BS*0.25; // let it drop a bit
- // Randomize a bit
- pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;*/
-
- /*
- Create the object
- */
- ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
-
- if(obj == NULL)
- {
- infostream<<"WARNING: item resulted in NULL object, "
- <<"not placing onto map"
- <<std::endl;
- }
- else
- {
- actionstream<<player->getName()<<" places "<<item->getName()
- <<" at "<<PP(p_over)<<std::endl;
-
- // Add the object to the environment
- m_env->addActiveObject(obj);
-
- infostream<<"Placed object"<<std::endl;
-
- if(g_settings->getBool("creative_mode") == false)
- {
- // Delete the right amount of items from the slot
- u16 dropcount = item->getDropCount();
-
- // Delete item if all gone
- if(item->getCount() <= dropcount)
- {
- if(item->getCount() < dropcount)
- infostream<<"WARNING: Server: dropped more items"
- <<" than the slot contains"<<std::endl;
-
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist)
- // Remove from inventory and send inventory
- ilist->deleteItem(item_i);
- }
- // Else decrement it
- else
- item->remove(dropcount);
-
- // Send inventory
- UpdateCrafting(peer_id);
- SendInventory(peer_id);
- }
- }
- }
-
- } // action == 1