+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ 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())
+ {
+ bool cannot_place_node = !build_priv;
+
+ try{
+ // Don't add a node if this is not a free space
+ MapNode n2 = m_env->getMap().getNode(p_above);
+ if(m_nodedef->get(n2).buildable_to == false)
+ {
+ infostream<<"Client "<<peer_id<<" tried to place"
+ <<" node in invalid position."<<std::endl;
+ cannot_place_node = true;
+ }
+ }
+ 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_above), BLOCK_EMERGE_FLAG_FROMDISK);
+ cannot_place_node = true;
+ }
+
+ if(cannot_place_node)
+ {
+ // Client probably has wrong data.
+ // Set block not sent, so that client will get
+ // a valid one.
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(p_above);
+ client->SetBlockNotSent(blockpos);
+ 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_nodedef->get(n).wall_mounted)
+ n.param2 = packDir(p_under - p_above);
+
+ // Calculate the direction for furnaces and chests and stuff
+ if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
+ {
+ v3f playerpos = player->getPosition();
+ v3f blockpos = intToFloat(p_above, 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_above, 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);
+ srp->m_inventory_not_sent = true;
+ }
+
+ /*
+ 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_above, 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);
+ }
+
+ /*
+ Run script hook
+ */
+ scriptapi_environment_on_placenode(m_lua, p_above, n, srp);
+
+ /*
+ Calculate special events
+ */
+
+ /*if(n.d == LEGN(m_nodedef, "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
+ {
+ if(!build_priv)
+ {
+ infostream<<"Not allowing player to place item: "
+ "no build privileges"<<std::endl;
+ return;
+ }
+
+ // Calculate a position for it
+ v3f pos = player_pos;
+ if(pointed.type == POINTEDTHING_NOTHING)
+ {
+ infostream<<"Not allowing player to place item: "
+ "pointing to nothing"<<std::endl;
+ return;
+ }
+ else if(pointed.type == POINTEDTHING_NODE)
+ {
+ pos = intToFloat(p_above, BS);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pos = pointed_object->getBasePosition();
+
+ // 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;
+ }
+
+ //pos.Y -= BS*0.45;
+ //pos.Y -= BS*0.25; // let it drop a bit
+
+ /*
+ Check that the block is loaded so that the item
+ can properly be added to the static list too
+ */
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
+ MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
+ if(block==NULL)
+ {
+ infostream<<"Error while placing item: "
+ "block not found"<<std::endl;
+ return;
+ }
+
+ actionstream<<player->getName()<<" places "<<item->getName()
+ <<" at "<<PP(pos)<<std::endl;
+
+ /*
+ Place the item
+ */
+ bool remove = item->dropOrPlace(m_env, srp, pos, true, -1);
+ if(remove && g_settings->getBool("creative_mode") == false)
+ {
+ InventoryList *ilist = player->inventory.getList("main");
+ if(ilist){
+ // Remove from inventory and send inventory
+ ilist->deleteItem(item_i);
+ srp->m_inventory_not_sent = true;
+ }
+ }
+ }
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ // Right click object
+
+ if(!build_priv)
+ return;
+
+ // Skip if object has been removed
+ if(pointed_object->m_removed)
+ return;
+
+ actionstream<<player->getName()<<" right-clicks object "
+ <<pointed.object_id<<std::endl;
+
+ // Do stuff
+ pointed_object->rightClick(srp);
+ }
+
+ } // action == 3
+
+ /*
+ 4: use
+ */
+ else if(action == 4)
+ {
+ 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;
+
+ // Requires build privs
+ if(!build_priv)
+ {
+ infostream<<"Not allowing player to use item: "
+ "no build privileges"<<std::endl;
+ return;
+ }