+ infostream<<"Server: password change successful for "<<playername
+ <<std::endl;
+ SendChatMessage(peer_id, L"Password change successful");
+ }
+ else if(command == TOSERVER_PLAYERITEM)
+ {
+ if (datasize < 2+2)
+ return;
+
+ u16 item = readU16(&data[2]);
+ player->wieldItem(item);
+ SendWieldedItem(player);
+ }
+ else if(command == TOSERVER_RESPAWN)
+ {
+ if(player->hp != 0)
+ return;
+
+ RespawnPlayer(player);
+
+ actionstream<<player->getName()<<" respawns at "
+ <<PP(player->getPosition()/BS)<<std::endl;
+ }
+ else if(command == TOSERVER_INTERACT)
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ /*
+ [0] u16 command
+ [2] u8 action
+ [3] u16 item
+ [5] u32 length of the next item
+ [9] serialized PointedThing
+ actions:
+ 0: start digging (from undersurface) or use
+ 1: stop digging (all parameters ignored)
+ 2: digging completed
+ 3: place block or item (to abovesurface)
+ 4: use item
+ */
+ u8 action = readU8(is);
+ u16 item_i = readU16(is);
+ std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+ PointedThing pointed;
+ pointed.deSerialize(tmp_is);
+
+ infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
+
+ v3f player_pos = srp->m_last_good_position;
+
+ // Update wielded item
+ srp->wieldItem(item_i);
+
+ // Get pointed to node (undefined if not POINTEDTYPE_NODE)
+ v3s16 p_under = pointed.node_undersurface;
+ v3s16 p_above = pointed.node_abovesurface;
+
+ // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
+ ServerActiveObject *pointed_object = NULL;
+ if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pointed_object = m_env->getActiveObject(pointed.object_id);
+ if(pointed_object == NULL)
+ {
+ infostream<<"TOSERVER_INTERACT: "
+ "pointed object is NULL"<<std::endl;
+ return;
+ }
+
+ }
+
+ /*
+ Check that target is reasonably close
+ (only when digging or placing things)
+ */
+ if(action == 0 || action == 2 || action == 3)
+ {
+ v3f pointed_pos = player_pos;
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ pointed_pos = intToFloat(p_under, BS);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pointed_pos = pointed_object->getBasePosition();
+ }
+
+ float d = player_pos.getDistanceFrom(pointed_pos);
+ float max_d = BS * 10; // Just some large enough value
+ if(d > max_d){
+ actionstream<<"Player "<<player->getName()
+ <<" tried to access "<<pointed.dump()
+ <<" from too far: "
+ <<"d="<<d<<", max_d="<<max_d
+ <<". ignoring."<<std::endl;
+ // Re-send block to revert change on client-side
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos, BS));
+ client->SetBlockNotSent(blockpos);
+ // Do nothing else
+ return;
+ }
+ }
+
+ /*
+ Make sure the player is allowed to do it
+ */
+ bool build_priv = (getPlayerPrivs(player) & PRIV_BUILD) != 0;
+ if(!build_priv)
+ {
+ infostream<<"Ignoring interaction from player "<<player->getName()
+ <<" because privileges are "<<getPlayerPrivs(player)
+ <<std::endl;
+ // NOTE: no return; here, fall through
+ }
+
+ /*
+ 0: start digging or punch object
+ */
+ if(action == 0)
+ {
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ /*
+ NOTE: This can be used in the future to check if
+ somebody is cheating, by checking the timing.
+ */
+ bool cannot_punch_node = !build_priv;
+
+ MapNode n(CONTENT_IGNORE);
+
+ try
+ {
+ n = m_env->getMap().getNode(p_under);
+ }
+ catch(InvalidPositionException &e)
+ {
+ infostream<<"Server: Not punching: Node not found."
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+ cannot_punch_node = true;
+ }
+
+ if(cannot_punch_node)
+ return;
+
+ /*
+ Run script hook
+ */
+ scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ if(!build_priv)
+ return;
+
+ // Skip if object has been removed
+ if(pointed_object->m_removed)
+ return;
+
+ actionstream<<player->getName()<<" punches object "
+ <<pointed.object_id<<std::endl;
+
+ // Do stuff
+ pointed_object->punch(srp);
+ }
+
+ } // action == 0
+