X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fserver.cpp;h=5646c0ac9c9dffdccff84b15f7e5ee00d83ce738;hb=cd563473fa298db3b910009f26ba263bacd84be9;hp=4cabcda0ca35e1a6893a48dc2b7823a71358c7e3;hpb=2a610b011ac2f289ebde692ab3dcf10dd4f0244f;p=oweals%2Fminetest.git diff --git a/src/server.cpp b/src/server.cpp index 4cabcda0c..5646c0ac9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1376,12 +1376,7 @@ void Server::AsyncRunStep() */ /* - Check player movements - - NOTE: Actually the server should handle player physics like the - client does and compare player's position to what is calculated - on our side. This is required when eg. players fly due to an - explosion. + Handle players */ { JMutexAutoLock lock(m_env_mutex); @@ -1404,6 +1399,15 @@ void Server::AsyncRunStep() (m_env->getPlayer(client->peer_id)); if(player==NULL) continue; + + /* + Check player movements + + NOTE: Actually the server should handle player physics like the + client does and compare player's position to what is calculated + on our side. This is required when eg. players fly due to an + explosion. + */ player->m_last_good_position_age += dtime; if(player->m_last_good_position_age >= 2.0){ float age = player->m_last_good_position_age; @@ -1425,6 +1429,17 @@ void Server::AsyncRunStep() } player->m_last_good_position_age = 0; } + + /* + Send player inventories and HPs if necessary + */ + if(player->m_inventory_not_sent){ + UpdateCrafting(player->peer_id); + SendInventory(player->peer_id); + } + if(player->m_hp_not_sent){ + SendPlayerHP(player); + } } } @@ -2069,8 +2084,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"Server: Cannot negotiate " "serialization version with peer " <getBool("strict_protocol_version_checking")) { - if(net_proto_version < PROTOCOL_VERSION) + if(net_proto_version != PROTOCOL_VERSION) { - SendAccessDenied(m_con, peer_id, - L"Your client is too old. Please upgrade."); + SendAccessDenied(m_con, peer_id, std::wstring( + L"Your client's version is not supported.\n" + L"Server version is ") + + narrow_to_wide(VERSION_STRING) + L"." + ); return; } } @@ -2338,6 +2361,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } Player *player = m_env->getPlayer(peer_id); + ServerRemotePlayer *srp = static_cast(player); if(player == NULL){ infostream<<"Server::ProcessData(): Cancelling: " @@ -2507,162 +2531,231 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) std::istringstream is(datastring, std::ios_base::binary); // Create an action InventoryAction *a = InventoryAction::deSerialize(is); - if(a != NULL) + if(a == NULL) { - // Create context - InventoryContext c; - c.current_player = player; + infostream<<"TOSERVER_INVENTORY_ACTION: " + <<"InventoryAction::deSerialize() returned NULL" + <getType() == IACTION_MOVE + && g_settings->getBool("creative_mode") == false) + { + InventoryList *rlist = player->inventory.getList("craftresult"); + assert(rlist); + InventoryList *clist = player->inventory.getList("craft"); + assert(clist); + InventoryList *mlist = player->inventory.getList("main"); + assert(mlist); + + IMoveAction *ma = (IMoveAction*)a; /* - Handle craftresult specially if not in creative mode + Disable moving items into craftresult from elsewhere */ - bool disable_action = false; - if(a->getType() == IACTION_MOVE - && g_settings->getBool("creative_mode") == false) + if(ma->to_inv == "current_player" + && ma->to_list == "craftresult" + && (ma->from_inv != "current_player" + || ma->from_list != "craftresult")) { - IMoveAction *ma = (IMoveAction*)a; - if(ma->to_inv == "current_player" && - ma->from_inv == "current_player") + infostream<<"Ignoring IMoveAction from " + <from_inv<<":"<from_list + <<" to "<to_inv<<":"<to_list + <<" because dst is craftresult" + <<" and src isn't craftresult"<from_inv == "current_player" + && ma->from_list == "craftresult" + && player->craftresult_is_preview) + { + /* + If the craftresult is placed on itself, crafting takes + place and result is moved into main list + */ + if(ma->to_inv == "current_player" + && ma->to_list == "craftresult") { - InventoryList *rlist = player->inventory.getList("craftresult"); - assert(rlist); - InventoryList *clist = player->inventory.getList("craft"); - assert(clist); - InventoryList *mlist = player->inventory.getList("main"); - assert(mlist); - /* - Craftresult is no longer preview if something - is moved into it - */ - if(ma->to_list == "craftresult" - && ma->from_list != "craftresult") - { - // If it currently is a preview, remove - // its contents - if(player->craftresult_is_preview) - { - rlist->deleteItem(0); - } - player->craftresult_is_preview = false; - } - /* - Crafting takes place if this condition is true. - */ - if(player->craftresult_is_preview && - ma->from_list == "craftresult") - { - player->craftresult_is_preview = false; - clist->decrementMaterials(1); - - /* Print out action */ - InventoryList *list = - player->inventory.getList("craftresult"); - assert(list); - InventoryItem *item = list->getItem(0); - std::string itemname = "NULL"; - if(item) - itemname = item->getName(); - actionstream<getName()<<" crafts " - <to_list == "craftresult" - && ma->from_list == "craftresult") - { - disable_action = true; - - InventoryItem *item1 = rlist->changeItem(0, NULL); - mlist->addItem(item1); + // Except if main list doesn't have free slots + if(mlist->getFreeSlots() == 0){ + infostream<<"Cannot craft: Main list doesn't have" + <<" free slots"<craftresult_is_preview = false; + clist->decrementMaterials(1); + + InventoryItem *item1 = rlist->changeItem(0, NULL); + mlist->addItem(item1); + + srp->m_inventory_not_sent = true; + + delete a; + return; } - // Disallow moving items if not allowed to build - else if((getPlayerPrivs(player) & PRIV_BUILD) == 0) - { - disable_action = true; - } - // if it's a locking chest, only allow the owner or server admins to move items - else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + /* + 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. + */ + do{ + Inventory *inv_to = 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"<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<getName()<<" crafts " + <apply(&c, this, m_env); + + delete a; + return; + } + + /* + Non-crafting move + */ + + // Disallow moving items in elsewhere than player's inventory + // if not allowed to build + if((getPlayerPrivs(player) & PRIV_BUILD) == 0 + && (ma->from_inv != "current_player" + || ma->to_inv != "current_player")) + { + infostream<<"Cannot move outside of player's inventory: " + <<"No build privilege"<from_inv != "current_player" + && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + { + Strfnd fn(ma->from_inv); + std::string id0 = fn.next(":"); + if(id0 == "nodemeta") { - Strfnd fn(ma->from_inv); - 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(",")); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); + if(meta->getOwner() != "" && + meta->getOwner() != 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() != ""){ - if(meta->getOwner() != player->getName()) - disable_action = true; - } + infostream<<"Cannot move item: " + "not owner of metadata" + <to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + } + // 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") { - Strfnd fn(ma->to_inv); - 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(",")); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); + if(meta->getOwner() != "" && + meta->getOwner() != 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() != ""){ - if(meta->getOwner() != player->getName()) - disable_action = true; - } + infostream<<"Cannot move item: " + "not owner of metadata" + <getType() == IACTION_DROP) + } + /* + Handle restrictions and special cases of the drop action + */ + else if(a->getType() == IACTION_DROP) + { + IDropAction *da = (IDropAction*)a; + // Disallow dropping items if not allowed to build + if((getPlayerPrivs(player) & PRIV_BUILD) == 0) { - IDropAction *da = (IDropAction*)a; - // Disallow dropping items if not allowed to build - if((getPlayerPrivs(player) & PRIV_BUILD) == 0) - { - disable_action = true; - } - // if it's a locking chest, only allow the owner or server admins to drop items - else if (da->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 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) + { + Strfnd fn(da->from_inv); + std::string id0 = fn.next(":"); + if(id0 == "nodemeta") { - Strfnd fn(da->from_inv); - 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(",")); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); + if(meta->getOwner() != "" && + meta->getOwner() != 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() != ""){ - if(meta->getOwner() != player->getName()) - disable_action = true; - } + infostream<<"Cannot move item: " + "not owner of metadata" + <apply(&c, this, m_env); - } - - // Eat the action - delete a; - } - else - { - infostream<<"TOSERVER_INVENTORY_ACTION: " - <<"InventoryAction::deSerialize() returned NULL" - <apply(&c, this, m_env); + // Eat the action + delete a; } else if(command == TOSERVER_CHAT_MESSAGE) { @@ -2911,7 +3004,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<m_inventory_not_sent = true; } item = NULL; if(mineral != MINERAL_NONE) - item = getDiggedMineralItem(mineral, this); + item = getDiggedMineralItem(mineral, this); // If not mineral if(item == NULL) @@ -3224,6 +3319,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { // Add a item to inventory player->inventory.addItem("main", item); + srp->m_inventory_not_sent = true; } } @@ -3365,6 +3461,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) ilist->deleteItem(item_i); else mitem->remove(1); + srp->m_inventory_not_sent = true; } /* @@ -3472,9 +3569,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(remove && g_settings->getBool("creative_mode") == false) { InventoryList *ilist = player->inventory.getList("main"); - if(ilist) + if(ilist){ // Remove from inventory and send inventory ilist->deleteItem(item_i); + srp->m_inventory_not_sent = true; + } } } } @@ -3526,12 +3625,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<", pointing at "<use(m_env, srp, pointed); + if(remove && g_settings->getBool("creative_mode") == false) { InventoryList *ilist = player->inventory.getList("main"); - if(ilist) + if(ilist){ // Remove from inventory and send inventory ilist->deleteItem(item_i); + srp->m_inventory_not_sent = true; + } } } // action == 4 @@ -3547,11 +3649,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Complete add_to_inventory_later srp->completeAddToInventoryLater(item_i); - - // Send inventory - // FIXME: Shouldn't be done unless something changed. - UpdateCrafting(player->peer_id); - SendInventory(player->peer_id); } else { @@ -3610,9 +3707,9 @@ void Server::inventoryModified(InventoryContext *c, std::string id) if(id == "current_player") { assert(c->current_player); - // Send inventory - UpdateCrafting(c->current_player->peer_id); - SendInventory(c->current_player->peer_id); + ServerRemotePlayer *srp = + static_cast(c->current_player); + srp->m_inventory_not_sent = true; return; } @@ -3904,9 +4001,12 @@ void Server::SendInventory(u16 peer_id) { DSTACK(__FUNCTION_NAME); - Player* player = m_env->getPlayer(peer_id); + ServerRemotePlayer* player = + static_cast(m_env->getPlayer(peer_id)); assert(player); + player->m_inventory_not_sent = false; + /* Serialize it */ @@ -4472,42 +4572,63 @@ void Server::UpdateCrafting(u16 peer_id) Player* player = m_env->getPlayer(peer_id); assert(player); + ServerRemotePlayer *srp = static_cast(player); - /* - Calculate crafting stuff - */ - if(g_settings->getBool("creative_mode") == false) + // No crafting in creative mode + if(g_settings->getBool("creative_mode")) + return; + + // Get the InventoryLists of the player in which we will operate + InventoryList *clist = player->inventory.getList("craft"); + assert(clist); + InventoryList *rlist = player->inventory.getList("craftresult"); + assert(rlist); + InventoryList *mlist = player->inventory.getList("main"); + assert(mlist); + + // If the result list is not a preview and is not empty, try to + // throw the item into main list + if(!player->craftresult_is_preview && rlist->getUsedSlots() != 0) { - InventoryList *clist = player->inventory.getList("craft"); - InventoryList *rlist = player->inventory.getList("craftresult"); - - if(rlist && rlist->getUsedSlots() == 0) - player->craftresult_is_preview = true; + // Grab item out of craftresult + InventoryItem *item = rlist->changeItem(0, NULL); + // 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); + // Inventory was modified + srp->m_inventory_not_sent = true; + } + + // If result list is empty, we will make it preview what would be + // crafted + 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(rlist && player->craftresult_is_preview) - { - rlist->clearItems(); - } - if(clist && rlist && player->craftresult_is_preview) - { - // Get result of crafting grid - - std::vector 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); - - InventoryItem *result = m_craftdef->getCraftResult(cpi, this); - //InventoryItem *result = craft_get_result(items, this); - if(result) - rlist->addItem(result); + // 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 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()); } - - } // if creative_mode == false + CraftPointerInput cpi(3, items); + + // Find out what is crafted and add it to result item slot + InventoryItem *result = m_craftdef->getCraftResult(cpi, this); + if(result) + rlist->addItem(result); + } } RemoteClient* Server::getClient(u16 peer_id)