+ else if(command == TOSERVER_PLAYERITEM)
+ {
+ if (datasize < 2+2)
+ return;
+
+ u16 item = readU16(&data[2]);
+ srp->setWieldIndex(item);
+ SendWieldedItem(srp);
+ }
+ else if(command == TOSERVER_RESPAWN)
+ {
+ if(player->hp != 0)
+ return;
+
+ RespawnPlayer(player);
+
+ actionstream<<player->getName()<<" respawns at "
+ <<PP(player->getPosition()/BS)<<std::endl;
+
+ // ActiveObject is added to environment in AsyncRunStep after
+ // the previous addition has been succesfully removed
+ }
+ else if(command == TOSERVER_REQUEST_TEXTURES) {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
+
+ core::list<TextureRequest> tosend;
+
+ u16 numtextures = readU16(is);
+
+ for(int i = 0; i < numtextures; i++) {
+
+ std::string name = deSerializeString(is);
+
+ tosend.push_back(TextureRequest(name));
+ infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl;
+ }
+
+ SendTexturesRequested(peer_id, tosend);
+
+ // Now the client should know about everything
+ // (definitions and textures)
+ getClient(peer_id)->definitions_sent = true;
+ }
+ 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;
+
+ if(player->hp == 0)
+ {
+ infostream<<"TOSERVER_INTERACT: "<<srp->getName()
+ <<" tried to interact, but is dead!"<<std::endl;
+ return;
+ }
+
+ v3f player_pos = srp->m_last_good_position;
+
+ // Update wielded item
+ if(srp->getWieldIndex() != item_i)
+ {
+ srp->setWieldIndex(item_i);
+ SendWieldedItem(srp);
+ }
+
+ // 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;
+ }
+
+ }
+
+ v3f pointed_pos_under = player_pos;
+ v3f pointed_pos_above = player_pos;
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ pointed_pos_under = intToFloat(p_under, BS);
+ pointed_pos_above = intToFloat(p_above, BS);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pointed_pos_under = pointed_object->getBasePosition();
+ pointed_pos_above = pointed_pos_under;
+ }
+
+ /*
+ Check that target is reasonably close
+ (only when digging or placing things)
+ */
+ if(action == 0 || action == 2 || action == 3)
+ {
+ float d = player_pos.getDistanceFrom(pointed_pos_under);
+ 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_under, BS));
+ client->SetBlockNotSent(blockpos);
+ // Do nothing else
+ return;
+ }
+ }
+
+ /*
+ Make sure the player is allowed to do it
+ */
+ if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
+ {
+ infostream<<"Ignoring interaction from player "<<player->getName()
+ <<" because privileges are "<<getPlayerPrivs(player)
+ <<std::endl;
+ return;
+ }
+
+ /*
+ 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.
+ */
+ 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);
+ }
+ if(n.getContent() != CONTENT_IGNORE)
+ scriptapi_node_on_punch(m_lua, p_under, n, srp);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ // 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, srp->m_time_from_last_punch);
+ srp->m_time_from_last_punch = 0;
+ }
+
+ } // action == 0
+
+ /*
+ 1: stop digging
+ */
+ else if(action == 1)
+ {
+ } // action == 1
+
+ /*
+ 2: Digging completed
+ */
+ else if(action == 2)
+ {
+ // Only complete digging of nodes
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ MapNode n(CONTENT_IGNORE);
+ try
+ {
+ n = m_env->getMap().getNode(p_under);
+ }
+ 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);
+ }
+ if(n.getContent() != CONTENT_IGNORE)
+ scriptapi_node_on_dig(m_lua, p_under, n, srp);
+ }
+ } // action == 2
+
+ /*
+ 3: place block or right-click object
+ */
+ else if(action == 3)
+ {
+ ItemStack item = srp->getWieldedItem();
+
+ // Reset build time counter
+ if(pointed.type == POINTEDTHING_NODE &&
+ item.getDefinition(m_itemdef).type == ITEM_NODE)
+ getClient(peer_id)->m_time_from_building = 0.0;
+
+ if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ // Right click object
+
+ // 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);
+ }
+ else if(scriptapi_item_on_place(m_lua,
+ item, srp, pointed))
+ {
+ // Placement was handled in lua
+
+ // Apply returned ItemStack
+ if(g_settings->getBool("creative_mode") == false)
+ srp->setWieldedItem(item);
+ }
+
+ } // action == 3
+
+ /*
+ 4: use
+ */
+ else if(action == 4)
+ {
+ ItemStack item = srp->getWieldedItem();
+
+ actionstream<<player->getName()<<" uses "<<item.name
+ <<", pointing at "<<pointed.dump()<<std::endl;
+
+ if(scriptapi_item_on_use(m_lua,
+ item, srp, pointed))
+ {
+ // Apply returned ItemStack
+ if(g_settings->getBool("creative_mode") == false)
+ srp->setWieldedItem(item);
+ }
+
+ } // action == 4
+
+ /*
+ Catch invalid actions
+ */
+ else
+ {
+ infostream<<"WARNING: Server: Invalid action "
+ <<action<<std::endl;
+ }
+ }