diff options
Diffstat (limited to 'src/server.cpp')
-rw-r--r-- | src/server.cpp | 976 |
1 files changed, 388 insertions, 588 deletions
diff --git a/src/server.cpp b/src/server.cpp index d704bf861..3c0cab2a9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -42,9 +42,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "script.h" #include "scriptapi.h" #include "nodedef.h" -#include "tooldef.h" +#include "itemdef.h" #include "craftdef.h" -#include "craftitemdef.h" #include "mapgen.h" #include "content_abm.h" #include "mods.h" @@ -853,10 +852,9 @@ Server::Server( m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"), m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"), m_lua(NULL), - m_toolmgr(createToolDefManager()), + m_itemdef(createItemDefManager()), m_nodedef(createNodeDefManager()), m_craftdef(createCraftDefManager()), - m_craftitemdef(createCraftItemDefManager()), m_thread(this), m_emergethread(this), m_time_counter(0), @@ -934,6 +932,9 @@ Server::Server( // Read Textures and calculate sha1 sums PrepareTextures(); + // Apply item aliases in the node definition manager + m_nodedef->updateAliases(m_itemdef); + // Initialize Environment m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, @@ -1042,10 +1043,9 @@ Server::~Server() // Delete Environment delete m_env; - delete m_toolmgr; + delete m_itemdef; delete m_nodedef; delete m_craftdef; - delete m_craftitemdef; // Deinitialize scripting infostream<<"Server: Deinitializing scripting"<<std::endl; @@ -2106,15 +2106,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) Send some initialization data */ - // Send tool definitions - SendToolDef(m_con, peer_id, m_toolmgr); + // Send item definitions + SendItemDef(m_con, peer_id, m_itemdef); // Send node definitions SendNodeDef(m_con, peer_id, m_nodedef); - // Send CraftItem definitions - SendCraftItemDef(m_con, peer_id, m_craftitemdef); - // Send texture announcement SendTextureAnnouncement(peer_id); @@ -2362,13 +2359,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } else if(command == TOSERVER_INVENTORY_ACTION) { - /*// Ignore inventory changes if in creative mode - if(g_settings->getBool("creative_mode") == true) - { - infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode" - <<std::endl; - return; - }*/ // Strip command and create a stream std::string datastring((char*)&data[2], datasize-2); infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl; @@ -2382,15 +2372,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<std::endl; return; } - // Create context - InventoryContext c; - c.current_player = player; /* Handle restrictions and special cases of the move action */ - if(a->getType() == IACTION_MOVE - && g_settings->getBool("creative_mode") == false) + if(a->getType() == IACTION_MOVE) { InventoryList *rlist = player->inventory.getList("craftresult"); assert(rlist); @@ -2401,17 +2387,28 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) IMoveAction *ma = (IMoveAction*)a; + ma->from_inv.applyCurrentPlayer(player->getName()); + ma->to_inv.applyCurrentPlayer(player->getName()); + + bool from_inv_is_current_player = + (ma->from_inv.type == InventoryLocation::PLAYER) && + (ma->from_inv.name == player->getName()); + + bool to_inv_is_current_player = + (ma->to_inv.type == InventoryLocation::PLAYER) && + (ma->to_inv.name == player->getName()); + /* Disable moving items into craftresult from elsewhere */ - if(ma->to_inv == "current_player" + if(to_inv_is_current_player && ma->to_list == "craftresult" - && (ma->from_inv != "current_player" + && (!from_inv_is_current_player || ma->from_list != "craftresult")) { infostream<<"Ignoring IMoveAction from " - <<ma->from_inv<<":"<<ma->from_list - <<" to "<<ma->to_inv<<":"<<ma->to_list + <<(ma->from_inv.dump())<<":"<<ma->from_list + <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list <<" because dst is craftresult" <<" and src isn't craftresult"<<std::endl; delete a; @@ -2421,74 +2418,66 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) /* Handle crafting (source is craftresult, which is preview) */ - if(ma->from_inv == "current_player" + if(from_inv_is_current_player && ma->from_list == "craftresult" - && player->craftresult_is_preview) + && player->craftresult_is_preview + && g_settings->getBool("creative_mode") == false) { + ItemStack crafting_result; + bool crafting_possible = GetCraftingResult(peer_id, + crafting_result, false); + /* - If the craftresult is placed on itself, crafting takes - place and result is moved into main list + If the craftresult is placed on itself, + crafting takes place and result is moved + into main list. */ - if(ma->to_inv == "current_player" + if(crafting_possible + && to_inv_is_current_player && ma->to_list == "craftresult") { - // Except if main list doesn't have free slots - if(mlist->getFreeSlots() == 0){ - infostream<<"Cannot craft: Main list doesn't have" - <<" free slots"<<std::endl; - delete a; - return; - } - - player->craftresult_is_preview = false; - clist->decrementMaterials(1); - - InventoryItem *item1 = rlist->changeItem(0, NULL); - mlist->addItem(item1); + if(mlist->roomForItem(crafting_result)) + { + actionstream<<player->getName() + <<" crafts " + <<crafting_result.getItemString() + <<std::endl; - srp->m_inventory_not_sent = true; + // Decrement crafting materials + GetCraftingResult(peer_id, crafting_result, true); + mlist->addItem(crafting_result); + rlist->clearItems(); + player->craftresult_is_preview = true; + srp->m_inventory_not_sent = true; + } - delete a; - return; } /* - Disable action if there are no free slots in - destination - - If the item is placed on an item that is not of the - same kind, the existing item will be first moved to - craftresult and immediately moved to the free slot. + Otherwise, if the destination is part of + the same player's inventory, crafting + takes place normally. */ - do{ - Inventory *inv_to = InventoryManager::getInventory(&c, ma->to_inv); - if(!inv_to) break; - InventoryList *list_to = inv_to->getList(ma->to_list); - if(!list_to) break; - if(list_to->getFreeSlots() == 0){ - infostream<<"Cannot craft: Destination doesn't have" - <<" free slots"<<std::endl; - delete a; - return; + else if(crafting_possible + && to_inv_is_current_player) + { + InventoryList *list = player->inventory.getList(ma->to_list); + if(list && list->itemFits(ma->to_i, crafting_result)) + { + actionstream<<player->getName() + <<" crafts " + <<crafting_result.getItemString() + <<std::endl; + + // Decrement crafting materials + GetCraftingResult(peer_id, crafting_result, true); + list->addItem(ma->to_i, crafting_result); + rlist->clearItems(); + player->craftresult_is_preview = true; + srp->m_inventory_not_sent = true; } - }while(0); // Allow break + } - /* - Ok, craft normally. - */ - player->craftresult_is_preview = false; - clist->decrementMaterials(1); - - /* Print out action */ - InventoryItem *item = rlist->getItem(0); - std::string itemstring = "NULL"; - if(item) - itemstring = item->getItemString(); - actionstream<<player->getName()<<" crafts " - <<itemstring<<std::endl; - - // Do the action - a->apply(&c, this, m_env); - + // Do not apply the action normally. delete a; return; } @@ -2498,63 +2487,38 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ // Disallow moving items in elsewhere than player's inventory - // if not allowed to build + // if not allowed to interact if((getPlayerPrivs(player) & PRIV_INTERACT) == 0 - && (ma->from_inv != "current_player" - || ma->to_inv != "current_player")) + && (from_inv_is_current_player + || to_inv_is_current_player)) { infostream<<"Cannot move outside of player's inventory: " - <<"No build privilege"<<std::endl; + <<"No interact privilege"<<std::endl; delete a; return; } - // If player is not an admin, check for ownership of src - if(ma->from_inv != "current_player" - && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + // If player is not an admin, check for ownership of src and dst + if((getPlayerPrivs(player) & PRIV_SERVER) == 0) { - Strfnd fn(ma->from_inv); - std::string id0 = fn.next(":"); - if(id0 == "nodemeta") + std::string owner_from = getInventoryOwner(ma->from_inv); + if(owner_from != "" && owner_from != player->getName()) { - v3s16 p; - p.X = stoi(fn.next(",")); - p.Y = stoi(fn.next(",")); - p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); - if(meta->getOwner() != "" && - meta->getOwner() != player->getName()) - { - infostream<<"Cannot move item: " - "not owner of metadata" - <<std::endl; - delete a; - return; - } + infostream<<"WARNING: "<<player->getName() + <<" tried to access an inventory that" + <<" belongs to "<<owner_from<<std::endl; + delete a; + return; } - } - // If player is not an admin, check for ownership of dst - if(ma->to_inv != "current_player" - && (getPlayerPrivs(player) & PRIV_SERVER) == 0) - { - Strfnd fn(ma->to_inv); - std::string id0 = fn.next(":"); - if(id0 == "nodemeta") + + std::string owner_to = getInventoryOwner(ma->to_inv); + if(owner_to != "" && owner_to != player->getName()) { - v3s16 p; - p.X = stoi(fn.next(",")); - p.Y = stoi(fn.next(",")); - p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); - if(meta->getOwner() != "" && - meta->getOwner() != player->getName()) - { - infostream<<"Cannot move item: " - "not owner of metadata" - <<std::endl; - delete a; - return; - } + infostream<<"WARNING: "<<player->getName() + <<" tried to access an inventory that" + <<" belongs to "<<owner_to<<std::endl; + delete a; + return; } } } @@ -2564,40 +2528,32 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else if(a->getType() == IACTION_DROP) { IDropAction *da = (IDropAction*)a; - // Disallow dropping items if not allowed to build + + da->from_inv.applyCurrentPlayer(player->getName()); + + // Disallow dropping items if not allowed to interact if((getPlayerPrivs(player) & PRIV_INTERACT) == 0) { delete a; return; } // If player is not an admin, check for ownership - else if (da->from_inv != "current_player" - && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + else if((getPlayerPrivs(player) & PRIV_SERVER) == 0) { - Strfnd fn(da->from_inv); - std::string id0 = fn.next(":"); - if(id0 == "nodemeta") + std::string owner_from = getInventoryOwner(da->from_inv); + if(owner_from != "" && owner_from != player->getName()) { - v3s16 p; - p.X = stoi(fn.next(",")); - p.Y = stoi(fn.next(",")); - p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); - if(meta->getOwner() != "" && - meta->getOwner() != player->getName()) - { - infostream<<"Cannot move item: " - "not owner of metadata" - <<std::endl; - delete a; - return; - } + infostream<<"WARNING: "<<player->getName() + <<" tried to access an inventory that" + <<" belongs to "<<owner_from<<std::endl; + delete a; + return; } } } // Do the action - a->apply(&c, this, m_env); + a->apply(this, srp); // Eat the action delete a; } @@ -2809,8 +2765,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; u16 item = readU16(&data[2]); - player->wieldItem(item); - SendWieldedItem(player); + srp->setWieldIndex(item); + SendWieldedItem(srp); } else if(command == TOSERVER_RESPAWN) { @@ -2880,7 +2836,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) v3f player_pos = srp->m_last_good_position; // Update wielded item - srp->wieldItem(item_i); + 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; @@ -2900,23 +2860,26 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } + 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) { - 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 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() @@ -2926,7 +2889,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<". ignoring."<<std::endl; // Re-send block to revert change on client-side RemoteClient *client = getClient(peer_id); - v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos, BS)); + v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); client->SetBlockNotSent(blockpos); // Do nothing else return; @@ -2936,8 +2899,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) /* Make sure the player is allowed to do it */ - bool build_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0; - if(!build_priv) + bool interact_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0; + if(!interact_priv) { infostream<<"Ignoring interaction from player "<<player->getName() <<" because privileges are "<<getPlayerPrivs(player) @@ -2956,7 +2919,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) NOTE: This can be used in the future to check if somebody is cheating, by checking the timing. */ - bool cannot_punch_node = !build_priv; + bool cannot_punch_node = !interact_priv; MapNode n(CONTENT_IGNORE); @@ -2984,7 +2947,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } else if(pointed.type == POINTEDTHING_OBJECT) { - if(!build_priv) + if(!interact_priv) return; // Skip if object has been removed @@ -3023,7 +2986,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) content_t material = CONTENT_IGNORE; u8 mineral = MINERAL_NONE; - bool cannot_remove_node = !build_priv; + bool cannot_remove_node = !interact_priv; MapNode n(CONTENT_IGNORE); try @@ -3114,64 +3077,44 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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; - } + ItemStack &item = mlist->getItem(item_i); + + // Get digging properties for material and tool + ToolDiggingProperties tp = + item.getToolDiggingProperties(m_itemdef); + DiggingProperties prop = + getDiggingProperties(material, &tp, m_nodedef); + item.addWear(prop.wear, m_itemdef); + srp->m_inventory_not_sent = true; } /* Add dug item to inventory */ - InventoryItem *item = NULL; + ItemStack item; if(mineral != MINERAL_NONE) item = getDiggedMineralItem(mineral, this); // If not mineral - if(item == NULL) + if(item.empty()) { 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); + item.deSerialize(dug_s, m_itemdef); } } - if(item != NULL) + if(!item.empty()) { // Add a item to inventory player->inventory.addItem("main", item); srp->m_inventory_not_sent = true; } - item = NULL; + item.clear(); { const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item; @@ -3179,12 +3122,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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); + item.deSerialize(extra_dug_s, m_itemdef); } } - if(item != NULL) + if(!item.empty()) { // Add a item to inventory player->inventory.addItem("main", item); @@ -3226,242 +3168,155 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ else if(action == 3) { - if(pointed.type == POINTEDTHING_NODE) + if(!interact_priv) { - 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; + infostream<<"Not allowing player " + <<player->getName()<<" to place item: " + <<"no interact privileges"<<std::endl; + 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; - } + ItemStack item = srp->getWieldedItem(); - 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; - } + if(pointed.type == POINTEDTHING_OBJECT) + { + // Right click object - // 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); + // Skip if object has been removed + if(pointed_object->m_removed) + return; - // 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; - } - } + actionstream<<player->getName()<<" right-clicks object " + <<pointed.object_id<<std::endl; - /* - 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. + // Do stuff + pointed_object->rightClick(srp); + } + else if(scriptapi_item_on_place(m_lua, + item, srp, pointed)) + { + // Placement was handled in lua - 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); + // Apply returned ItemStack + if(g_settings->getBool("creative_mode") == false) + srp->setWieldedItem(item); + } + else if(pointed.type == POINTEDTHING_NODE && + item.getDefinition(m_itemdef).type == ITEM_NODE) + { + bool cannot_place_node = !interact_priv; - 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++) + 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) { - u16 peer_id = *i; - RemoteClient *client = getClient(peer_id); - if(client==NULL) - continue; - client->SetBlocksNotSent(modified_blocks); + infostream<<"Client "<<peer_id<<" tried to place" + <<" node in invalid position."<<std::endl; + cannot_place_node = true; } - - /* - 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 + catch(InvalidPositionException &e) { - if(!build_priv) - { - infostream<<"Not allowing player to place item: " - "no build privileges"<<std::endl; - return; - } + 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; + } - // 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(); + 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; + } - // 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; - } + // Reset build time counter + getClient(peer_id)->m_time_from_building = 0.0; - //pos.Y -= BS*0.45; - //pos.Y -= BS*0.25; // let it drop a bit + // Create node data + MapNode n(m_nodedef, item.name, 0, 0); - /* - 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 material " + <<item.name + <<" at "<<PP(p_under)<<std::endl; - actionstream<<player->getName()<<" places "<<item->getName() - <<" at "<<PP(pos)<<std::endl; + // Calculate direction for wall mounted stuff + if(m_nodedef->get(n).wall_mounted) + n.param2 = packDir(p_under - p_above); - /* - 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; - } + // 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; } } - } - else if(pointed.type == POINTEDTHING_OBJECT) - { - // Right click object - if(!build_priv) - return; + /* + Send to all close-by players + */ + core::list<u16> far_players; + sendAddNode(p_above, n, 0, &far_players, 30); + + /* + Handle inventory + */ + if(g_settings->getBool("creative_mode") == false) + { + // Remove from inventory and send inventory + item.remove(1); + srp->setWieldedItem(item); + } - // Skip if object has been removed - if(pointed_object->m_removed) - return; + /* + Add node. - actionstream<<player->getName()<<" right-clicks object " - <<pointed.object_id<<std::endl; + 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); - // Do stuff - pointed_object->rightClick(srp); + 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); } } // action == 3 @@ -3471,38 +3326,25 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ 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) + // Requires interact privs + if(!interact_priv) { infostream<<"Not allowing player to use item: " - "no build privileges"<<std::endl; + "no interact privileges"<<std::endl; return; } - actionstream<<player->getName()<<" uses "<<item->getName() + ItemStack item = srp->getWieldedItem(); + + actionstream<<player->getName()<<" uses "<<item.name <<", pointing at "<<pointed.dump()<<std::endl; - bool remove = item->use(m_env, srp, pointed); - - if(remove && g_settings->getBool("creative_mode") == false) + if(scriptapi_item_on_use(m_lua, + item, srp, pointed)) { - InventoryList *ilist = player->inventory.getList("main"); - if(ilist){ - // Remove from inventory and send inventory - ilist->deleteItem(item_i); - srp->m_inventory_not_sent = true; - } + // Apply returned ItemStack + if(g_settings->getBool("creative_mode") == false) + srp->setWieldedItem(item); } } // action == 4 @@ -3515,9 +3357,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"WARNING: Server: Invalid action " <<action<<std::endl; } - - // Complete add_to_inventory_later - srp->completeAddToInventoryLater(item_i); } else { @@ -3549,6 +3388,9 @@ Inventory* Server::getInventory(const InventoryLocation &loc) case InventoryLocation::UNDEFINED: {} break; + case InventoryLocation::CURRENT_PLAYER: + {} + break; case InventoryLocation::PLAYER: { Player *player = m_env->getPlayer(loc.name.c_str()); @@ -3570,6 +3412,33 @@ Inventory* Server::getInventory(const InventoryLocation &loc) } return NULL; } +std::string Server::getInventoryOwner(const InventoryLocation &loc) +{ + switch(loc.type){ + case InventoryLocation::UNDEFINED: + {} + break; + case InventoryLocation::CURRENT_PLAYER: + {} + break; + case InventoryLocation::PLAYER: + { + return loc.name; + } + break; + case InventoryLocation::NODEMETA: + { + NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p); + if(!meta) + return ""; + return meta->getOwner(); + } + break; + default: + assert(0); + } + return ""; +} void Server::setInventoryModified(const InventoryLocation &loc) { switch(loc.type){ @@ -3604,64 +3473,6 @@ void Server::setInventoryModified(const InventoryLocation &loc) assert(0); } } -#if 0 -Inventory* Server::getInventory(InventoryContext *c, std::string id) -{ - if(id == "current_player") - { - assert(c->current_player); - return &(c->current_player->inventory); - } - - Strfnd fn(id); - std::string id0 = fn.next(":"); - - if(id0 == "nodemeta") - { - v3s16 p; - p.X = stoi(fn.next(",")); - p.Y = stoi(fn.next(",")); - p.Z = stoi(fn.next(",")); - - InventoryLocation loc; - loc.setNodeMeta(p); - return getInventory(loc); - } - - infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl; - return NULL; -} -void Server::inventoryModified(InventoryContext *c, std::string id) -{ - if(id == "current_player") - { - assert(c->current_player); - ServerRemotePlayer *srp = - static_cast<ServerRemotePlayer*>(c->current_player); - srp->m_inventory_not_sent = true; - return; - } - - Strfnd fn(id); - std::string id0 = fn.next(":"); - - if(id0 == "nodemeta") - { - v3s16 p; - p.X = stoi(fn.next(",")); - p.Y = stoi(fn.next(",")); - p.Z = stoi(fn.next(",")); - v3s16 blockpos = getNodeBlockPos(p); - - InventoryLocation loc; - loc.setNodeMeta(p); - setInventoryModified(loc); - return; - } - - infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl; -} -#endif core::list<PlayerInfo> Server::getPlayerInfo() { @@ -3783,8 +3594,8 @@ void Server::SendDeathscreen(con::Connection &con, u16 peer_id, con.Send(peer_id, 0, data, true); } -void Server::SendToolDef(con::Connection &con, u16 peer_id, - IToolDefManager *tooldef) +void Server::SendItemDef(con::Connection &con, u16 peer_id, + IItemDefManager *itemdef) { DSTACK(__FUNCTION_NAME); std::ostringstream os(std::ios_base::binary); @@ -3792,16 +3603,18 @@ void Server::SendToolDef(con::Connection &con, u16 peer_id, /* u16 command u32 length of the next item - serialized ToolDefManager + zlib-compressed serialized ItemDefManager */ - writeU16(os, TOCLIENT_TOOLDEF); + writeU16(os, TOCLIENT_ITEMDEF); std::ostringstream tmp_os(std::ios::binary); - tooldef->serialize(tmp_os); - os<<serializeLongString(tmp_os.str()); + itemdef->serialize(tmp_os); + std::ostringstream tmp_os2(std::ios::binary); + compressZlib(tmp_os.str(), tmp_os2); + os<<serializeLongString(tmp_os2.str()); // Make data buffer std::string s = os.str(); - infostream<<"Server::SendToolDef(): Sending tool definitions: size=" + infostream<<"Server::SendItemDef(): Sending item definitions: size=" <<s.size()<<std::endl; SharedBuffer<u8> data((u8*)s.c_str(), s.size()); // Send as reliable @@ -3817,12 +3630,14 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id, /* u16 command u32 length of the next item - serialized NodeDefManager + zlib-compressed serialized NodeDefManager */ writeU16(os, TOCLIENT_NODEDEF); std::ostringstream tmp_os(std::ios::binary); nodedef->serialize(tmp_os); - os<<serializeLongString(tmp_os.str()); + std::ostringstream tmp_os2(std::ios::binary); + compressZlib(tmp_os.str(), tmp_os2); + os<<serializeLongString(tmp_os2.str()); // Make data buffer std::string s = os.str(); @@ -3833,31 +3648,6 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id, con.Send(peer_id, 0, data, true); } -void Server::SendCraftItemDef(con::Connection &con, u16 peer_id, - ICraftItemDefManager *craftitemdef) -{ - DSTACK(__FUNCTION_NAME); - std::ostringstream os(std::ios_base::binary); - - /* - u16 command - u32 length of the next item - serialized CraftItemDefManager - */ - writeU16(os, TOCLIENT_CRAFTITEMDEF); - std::ostringstream tmp_os(std::ios::binary); - craftitemdef->serialize(tmp_os); - os<<serializeLongString(tmp_os.str()); - - // Make data buffer - std::string s = os.str(); - infostream<<"Server::SendCraftItemDef(): Sending craft item definitions: size=" - <<s.size()<<std::endl; - SharedBuffer<u8> data((u8*)s.c_str(), s.size()); - // Send as reliable - con.Send(peer_id, 0, data, true); -} - /* Non-static send methods */ @@ -3891,28 +3681,18 @@ void Server::SendInventory(u16 peer_id) m_con.Send(peer_id, 0, data, true); } -std::string getWieldedItemString(const Player *player) -{ - const InventoryItem *item = player->getWieldItem(); - if (item == NULL) - return std::string(""); - std::ostringstream os(std::ios_base::binary); - item->serialize(os); - return os.str(); -} - -void Server::SendWieldedItem(const Player* player) +void Server::SendWieldedItem(const ServerRemotePlayer* srp) { DSTACK(__FUNCTION_NAME); - assert(player); + assert(srp); std::ostringstream os(std::ios_base::binary); writeU16(os, TOCLIENT_PLAYERITEM); writeU16(os, 1); - writeU16(os, player->peer_id); - os<<serializeString(getWieldedItemString(player)); + writeU16(os, srp->peer_id); + os<<serializeString(srp->getWieldedItem().getItemString()); // Make data buffer std::string s = os.str(); @@ -3934,8 +3714,10 @@ void Server::SendPlayerItems() for(i = players.begin(); i != players.end(); ++i) { Player *p = *i; + ServerRemotePlayer *srp = + static_cast<ServerRemotePlayer*>(p); writeU16(os, p->peer_id); - os<<serializeString(getWieldedItemString(p)); + os<<serializeString(srp->getWieldedItem().getItemString()); } // Make data buffer @@ -4576,6 +4358,44 @@ void Server::RespawnPlayer(Player *player) SendPlayerHP(player); } +bool Server::GetCraftingResult(u16 peer_id, ItemStack &result, bool decrementInput) +{ + DSTACK(__FUNCTION_NAME); + + Player* player = m_env->getPlayer(peer_id); + assert(player); + + // Get the crafting InventoryList of the player in which we will operate + InventoryList *clist = player->inventory.getList("craft"); + assert(clist); + + // Mangle crafting grid to an another format + CraftInput ci; + ci.method = CRAFT_METHOD_NORMAL; + ci.width = 3; + for(u16 i=0; i<9; i++) + { + ci.items.push_back(clist->getItem(i)); + } + + // Find out what is crafted and add it to result item slot + CraftOutput co; + bool found = m_craftdef->getCraftResult(ci, co, decrementInput, this); + if(found) + result.deSerialize(co.item, m_itemdef); + + if(decrementInput) + { + // CraftInput has been changed, apply changes in clist + for(u16 i=0; i<9; i++) + { + clist->changeItem(i, ci.items[i]); + } + } + + return found; +} + void Server::UpdateCrafting(u16 peer_id) { DSTACK(__FUNCTION_NAME); @@ -4601,12 +4421,11 @@ void Server::UpdateCrafting(u16 peer_id) if(!player->craftresult_is_preview && rlist->getUsedSlots() != 0) { // Grab item out of craftresult - InventoryItem *item = rlist->changeItem(0, NULL); + ItemStack item = rlist->changeItem(0, ItemStack()); // Try to put in main - InventoryItem *leftover = mlist->addItem(item); - // If there are leftovers, put them back to craftresult and - // delete leftovers - delete rlist->addItem(leftover); + ItemStack leftover = mlist->addItem(item); + // If there are leftovers, put them back to craftresult + rlist->addItem(leftover); // Inventory was modified srp->m_inventory_not_sent = true; } @@ -4616,28 +4435,17 @@ void Server::UpdateCrafting(u16 peer_id) if(rlist->getUsedSlots() == 0) player->craftresult_is_preview = true; - // If it is a preview, clear the possible old preview in it - if(player->craftresult_is_preview) - rlist->clearItems(); - // If it is a preview, find out what is the crafting result // and put it in if(player->craftresult_is_preview) { - // Mangle crafting grid to an another format - std::vector<InventoryItem*> items; - for(u16 i=0; i<9; i++){ - if(clist->getItem(i) == NULL) - items.push_back(NULL); - else - items.push_back(clist->getItem(i)->clone()); - } - CraftPointerInput cpi(3, items); + // Clear the possible old preview in it + rlist->clearItems(); - // Find out what is crafted and add it to result item slot - InventoryItem *result = m_craftdef->getCraftResult(cpi, this); - if(result) - rlist->addItem(result); + // Put the new preview in + ItemStack crafting_result; + if(GetCraftingResult(peer_id, crafting_result, false)) + rlist->addItem(crafting_result); } } @@ -4734,9 +4542,9 @@ void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate) // IGameDef interface // Under envlock -IToolDefManager* Server::getToolDefManager() +IItemDefManager* Server::getItemDefManager() { - return m_toolmgr; + return m_itemdef; } INodeDefManager* Server::getNodeDefManager() { @@ -4746,10 +4554,6 @@ ICraftDefManager* Server::getCraftDefManager() { return m_craftdef; } -ICraftItemDefManager* Server::getCraftItemDefManager() -{ - return m_craftitemdef; -} ITextureSource* Server::getTextureSource() { return NULL; @@ -4759,9 +4563,9 @@ u16 Server::allocateUnknownNodeId(const std::string &name) return m_nodedef->allocateDummy(name); } -IWritableToolDefManager* Server::getWritableToolDefManager() +IWritableItemDefManager* Server::getWritableItemDefManager() { - return m_toolmgr; + return m_itemdef; } IWritableNodeDefManager* Server::getWritableNodeDefManager() { @@ -4771,10 +4575,6 @@ IWritableCraftDefManager* Server::getWritableCraftDefManager() { return m_craftdef; } -IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager() -{ - return m_craftitemdef; -} const ModSpec* Server::getModSpec(const std::string &modname) { @@ -4874,7 +4674,7 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id) { // Warning: double code below // Backup actual inventory - player->inventory_backup = new Inventory(); + player->inventory_backup = new Inventory(m_itemdef); *(player->inventory_backup) = player->inventory; // Set creative inventory player->resetInventory(); @@ -4919,7 +4719,7 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id) { // Warning: double code above // Backup actual inventory - player->inventory_backup = new Inventory(); + player->inventory_backup = new Inventory(m_itemdef); *(player->inventory_backup) = player->inventory; // Set creative inventory player->resetInventory(); |