X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fserver.cpp;h=63bf794ab4ee191f15df762bcf380e470f556840;hb=618314985d6a632ccfd2001d969d32a5ee6e4ca1;hp=3b2b452254547031cf49938f8a9b5d012ff9f6dd;hpb=932988af4650cdd844669d4cd238907409413db6;p=minetest.git diff --git a/src/server.cpp b/src/server.cpp index 3b2b45225..63bf794ab 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -27,13 +27,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "main.h" #include "constants.h" #include "voxel.h" -#include "materials.h" -#include "mineral.h" #include "config.h" #include "servercommand.h" #include "filesys.h" #include "content_mapnode.h" -#include "content_craft.h" #include "content_nodemeta.h" #include "mapblock.h" #include "serverobject.h" @@ -43,12 +40,15 @@ 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 "content_sao.h" // For PlayerSAO +#include "mods.h" +#include "sha1.h" +#include "base64.h" +#include "tool.h" +#include "utility_string.h" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -109,6 +109,10 @@ void * ServerThread::Thread() { infostream<<"Server: PeerNotFoundException"<setAsyncFatalError(e.what()); + } } END_DEBUG_EXCEPTION_HANDLER(errorstream) @@ -250,7 +254,7 @@ void * EmergeThread::Thread() t.stop(true); // Hide output } - { + do{ // enable break // Lock environment again to access the map JMutexAutoLock envlock(m_server->m_env_mutex); @@ -263,6 +267,11 @@ void * EmergeThread::Thread() // Get central block block = map.getBlockNoCreateNoEx(p); + + // If block doesn't exist, don't try doing anything with it + // This happens if the block is not in generation boundaries + if(!block) + break; /* Do some post-generate stuff @@ -286,7 +295,7 @@ void * EmergeThread::Thread() // Activate objects and stuff m_server->m_env->activateBlock(block, 0); - } + }while(false); } if(block == NULL) @@ -820,130 +829,32 @@ void PlayerInfo::PrintLine(std::ostream *s) (*s)< &l) -{ - core::list::Iterator i; - u32 checksum = 1; - u32 a = 10; - for(i=l.begin(); i!=l.end(); i++) - { - checksum += a * (i->id+1); - checksum ^= 0x435aafcd; - a *= 10; - } - return checksum; -} - -/* - Mods -*/ - -struct ModSpec -{ - std::string name; - std::string path; - std::set depends; - std::set unsatisfied_depends; - - ModSpec(const std::string &name_="", const std::string path_="", - const std::set &depends_=std::set()): - name(name_), - path(path_), - depends(depends_), - unsatisfied_depends(depends_) - {} -}; - -// Get a dependency-sorted list of ModSpecs -static core::list getMods(core::list &modspaths) -{ - std::queue mods_satisfied; - core::list mods_unsorted; - core::list mods_sorted; - for(core::list::Iterator i = modspaths.begin(); - i != modspaths.end(); i++){ - std::string modspath = *i; - std::vector dirlist = fs::GetDirListing(modspath); - for(u32 j=0; j depends; - std::ifstream is((modpath+DIR_DELIM+"depends.txt").c_str(), - std::ios_base::binary); - while(is.good()){ - std::string dep; - std::getline(is, dep); - dep = trim(dep); - if(dep != "") - depends.insert(dep); - } - ModSpec spec(modname, modpath, depends); - mods_unsorted.push_back(spec); - if(depends.empty()) - mods_satisfied.push(spec); - } - } - // Sort by depencencies - while(!mods_satisfied.empty()){ - ModSpec mod = mods_satisfied.front(); - mods_satisfied.pop(); - mods_sorted.push_back(mod); - for(core::list::Iterator i = mods_unsorted.begin(); - i != mods_unsorted.end(); i++){ - ModSpec &mod2 = *i; - if(mod2.unsatisfied_depends.empty()) - continue; - mod2.unsatisfied_depends.erase(mod.name); - if(!mod2.unsatisfied_depends.empty()) - continue; - mods_satisfied.push(mod2); - } - } - // Check unsatisfied dependencies - for(core::list::Iterator i = mods_unsorted.begin(); - i != mods_unsorted.end(); i++){ - ModSpec &mod = *i; - if(mod.unsatisfied_depends.empty()) - continue; - errorstream<<"mod \""<::iterator - i = mod.unsatisfied_depends.begin(); - i != mod.unsatisfied_depends.end(); i++){ - errorstream<<" \""<<(*i)<<"\""; - } - errorstream<<". Loading nevertheless."<::const_iterator i = m_gamespec.addon_paths.begin(); + i != m_gamespec.addon_paths.end(); i++) + infostream<<"- addons: "<<(*i)<::const_iterator i = m_gamespec.addon_paths.begin(); + i != m_gamespec.addon_paths.end(); i++) + m_modspaths.push_front((*i) + DIR_DELIM + "mods"); + + // Print out mod search paths + for(core::list::Iterator i = m_modspaths.begin(); + i != m_modspaths.end(); i++){ + std::string modspath = *i; + infostream<<"- mods: "<::Iterator i = m_mods.begin(); + i != m_mods.end(); i++){ + const ModSpec &mod = *i; + infostream< mods = getMods(m_modspaths); - for(core::list::Iterator i = mods.begin(); - i != mods.end(); i++){ - ModSpec mod = *i; - infostream<<"Server: Loading mod \""<::Iterator i = m_mods.begin(); + i != m_mods.end(); i++){ + const ModSpec &mod = *i; std::string scriptpath = mod.path + DIR_DELIM + "init.lua"; - bool success = script_load(m_lua, scriptpath.c_str()); + infostream<<" ["<updateAliases(m_itemdef); + // Initialize Environment - m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, + m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua, this, this); // Give environment reference to scripting api @@ -1012,15 +979,15 @@ Server::Server( m_env->getMap().addEventReceiver(this); // If file exists, load environment metadata - if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt")) + if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt")) { infostream<<"Server: Loading environment metadata"<loadMeta(m_mapsavedir); + m_env->loadMeta(m_path_world); } // Load players infostream<<"Server: Loading players"<deSerializePlayers(m_mapsavedir); + m_env->deSerializePlayers(m_path_world); /* Add some test ActiveBlockModifiers to environment @@ -1030,7 +997,7 @@ Server::Server( Server::~Server() { - infostream<<"Server::~Server()"<serializePlayers(m_mapsavedir); + m_env->serializePlayers(m_path_world); /* Save environment metadata */ infostream<<"Server: Saving environment metadata"<saveMeta(m_mapsavedir); + m_env->saveMeta(m_path_world); } /* @@ -1108,10 +1075,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"<__| \\___ >____ > |__| "<m_last_good_position_age += dtime; - if(player->m_last_good_position_age >= 2.0){ + if(player->m_last_good_position_age >= 1.0){ float age = player->m_last_good_position_age; v3f diff = (player->getPosition() - player->m_last_good_position); float d_vert = diff.Y; @@ -1333,9 +1317,10 @@ void Server::AsyncRunStep() } /* - Handle player HPs + Handle player HPs (die if hp=0) */ - HandlePlayerHP(player, 0); + if(player->hp == 0 && player->m_hp_not_sent) + DiePlayer(player); /* Send player inventories and HPs if necessary @@ -1347,6 +1332,15 @@ void Server::AsyncRunStep() if(player->m_hp_not_sent){ SendPlayerHP(player); } + + /* + Add to environment + */ + if(!player->m_is_in_environment){ + player->m_removed = false; + player->setId(0); + m_env->addActiveObject(player); + } } } @@ -1551,7 +1545,7 @@ void Server::AsyncRunStep() // Send as reliable m_con.Send(client->peer_id, 0, reply, true); - infostream<<"Server: Sent object remove/add: " + verbosestream<<"Server: Sent object remove/add: " <= 4) disable_single_change_sending = true; - bool got_any_events = false; + int event_count = m_unsent_map_edit_queue.size(); // We'll log the amount of each Profiler prof; while(m_unsent_map_edit_queue.size() != 0) { - got_any_events = true; - MapEditEvent* event = m_unsent_map_edit_queue.pop_front(); // Players far away from the change are stored here. @@ -1813,10 +1805,12 @@ void Server::AsyncRunStep() break;*/ } - if(got_any_events) - { + if(event_count >= 5){ infostream<<"Server: MapEditEvents:"<= g_settings->getFloat("server_map_save_interval")) { counter = 0.0; + JMutexAutoLock lock(m_env_mutex); ScopeProfiler sp(g_profiler, "Server: saving stuff"); @@ -1850,21 +1845,18 @@ void Server::AsyncRunStep() if(m_authmanager.isModified()) m_authmanager.save(); - //Bann stuff + //Ban stuff if(m_banmanager.isModified()) m_banmanager.save(); - // Map - JMutexAutoLock lock(m_env_mutex); - // Save changed parts of map m_env->getMap().save(MOD_STATE_WRITE_NEEDED); // Save players - m_env->serializePlayers(m_mapsavedir); + m_env->serializePlayers(m_path_world); // Save environment metadata - m_env->saveMeta(m_mapsavedir); + m_env->saveMeta(m_path_world); } } } @@ -1917,6 +1909,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); + ScopeProfiler sp(g_profiler, "Server::ProcessData"); + try{ Address address = m_con.GetPeerAddress(peer_id); @@ -1936,6 +1930,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <serialization_version; @@ -1957,7 +1953,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 2+1+PLAYERNAME_SIZE) return; - infostream<<"Server: Got TOSERVER_INIT from " + verbosestream<<"Server: Got TOSERVER_INIT from " <get("name")) { + actionstream<<"Server: "<m_removed = false; - player->setId(0); - m_env->addActiveObject(player); - /* Answer with a TOCLIENT_INIT */ @@ -2155,7 +2160,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(command == TOSERVER_INIT2) { - infostream<<"Server: Got TOSERVER_INIT2 from " + verbosestream<<"Server: Got TOSERVER_INIT2 from " <hp == 0) + SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0)); + // Send time of day { SharedBuffer data = makePacket_TOCLIENT_TIME_OF_DAY( @@ -2200,9 +2209,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) m_con.Send(peer_id, 0, data, true); } - // Now the client should know about everything - getClient(peer_id)->definitions_sent = true; - // Send information about server to player in chat SendChatMessage(peer_id, getStatusString()); @@ -2226,11 +2232,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER"); } - /* - Check HP, respawn if necessary - */ - HandlePlayerHP(player, 0); - /* Print out action */ @@ -2425,16 +2426,9 @@ 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" - <getType() == IACTION_MOVE) { - 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; + ma->from_inv.applyCurrentPlayer(player->getName()); + ma->to_inv.applyCurrentPlayer(player->getName()); + + setInventoryModified(ma->from_inv); + setInventoryModified(ma->to_inv); + + 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 + Disable moving items out of craftpreview */ - if(ma->to_inv == "current_player" - && ma->to_list == "craftresult" - && (ma->from_inv != "current_player" - || ma->from_list != "craftresult")) + if(ma->from_list == "craftpreview") { infostream<<"Ignoring IMoveAction from " - <from_inv<<":"<from_list - <<" to "<to_inv<<":"<to_list - <<" because dst is craftresult" - <<" and src isn't craftresult"<from_inv.dump())<<":"<from_list + <<" to "<<(ma->to_inv.dump())<<":"<to_list + <<" because src is "<from_list<from_inv == "current_player" - && ma->from_list == "craftresult" - && player->craftresult_is_preview) + if(ma->to_list == "craftpreview" || ma->to_list == "craftresult") { - /* - 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") - { - // 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; - } - /* - 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); - + infostream<<"Ignoring IMoveAction from " + <<(ma->from_inv.dump())<<":"<from_list + <<" to "<<(ma->to_inv.dump())<<":"<to_list + <<" because dst is "<to_list<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"<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" - <getName() + <<" tried to access an inventory that" + <<" belongs to "<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" - <getName() + <<" tried to access an inventory that" + <<" belongs to "<getType() == IACTION_DROP) { IDropAction *da = (IDropAction*)a; - // Disallow dropping items if not allowed to build + + da->from_inv.applyCurrentPlayer(player->getName()); + + setInventoryModified(da->from_inv); + + // 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) + { + std::string owner_from = getInventoryOwner(da->from_inv); + if(owner_from != "" && owner_from != player->getName()) + { + infostream<<"WARNING: "<getName() + <<" tried to access an inventory that" + <<" belongs to "<getType() == IACTION_CRAFT) + { + ICraftAction *ca = (ICraftAction*)a; + + ca->craft_inv.applyCurrentPlayer(player->getName()); + + setInventoryModified(ca->craft_inv); + + //bool craft_inv_is_current_player = + // (ca->craft_inv.type == InventoryLocation::PLAYER) && + // (ca->craft_inv.name == player->getName()); + + // Disallow crafting if not allowed to interact + if((getPlayerPrivs(player) & PRIV_INTERACT) == 0) + { + infostream<<"Cannot craft: " + <<"No interact privilege"<from_inv); - std::string id0 = fn.next(":"); - if(id0 == "nodemeta") + std::string owner_craft = getInventoryOwner(ca->craft_inv); + if(owner_craft != "" && owner_craft != 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" - <getName() + <<" tried to access an inventory that" + <<" belongs to "<apply(&c, this, m_env); + a->apply(this, srp, this); // Eat the action delete a; } @@ -2791,16 +2730,25 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) std::istringstream is(datastring, std::ios_base::binary); u8 damage = readU8(is); + ServerRemotePlayer *srp = static_cast(player); + if(g_settings->getBool("enable_damage")) { actionstream<getName()<<" damaged by " <<(int)damage<<" hp at "<getPosition()/BS) <setHP(srp->getHP() - damage); + + if(srp->getHP() == 0 && srp->m_hp_not_sent) + DiePlayer(srp); + + if(srp->m_hp_not_sent) + SendPlayerHP(player); } else { + // Force send (to correct the client's predicted HP) SendPlayerHP(player); } } @@ -2872,24 +2820,46 @@ 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) { if(player->hp != 0) return; - srp->m_respawn_active = false; - RespawnPlayer(player); actionstream<getName()<<" respawns at " <getPosition()/BS)<m_removed = false; - srp->setId(0); - m_env->addActiveObject(srp); + + core::list tosend; + u16 numtextures = readU16(is); + + infostream<<"Sending "<definitions_sent = true; } else if(command == TOSERVER_INTERACT) { @@ -2915,12 +2885,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) PointedThing pointed; pointed.deSerialize(tmp_is); - infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<getName() + <<" tried to interact, but is dead!"<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; @@ -2933,31 +2915,34 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) pointed_object = m_env->getActiveObject(pointed.object_id); if(pointed_object == NULL) { - infostream<<"TOSERVER_INTERACT: " + verbosestream<<"TOSERVER_INTERACT: " "pointed object is NULL"<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 max_d = BS * 10; // Just some large enough value + float d = player_pos.getDistanceFrom(pointed_pos_under); + float max_d = BS * 14; // Just some large enough value if(d > max_d){ actionstream<<"Player "<getName() <<" tried to access "<SetBlockNotSent(blockpos); // Do nothing else return; @@ -2976,13 +2961,12 @@ 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) + if((getPlayerPrivs(player) & PRIV_INTERACT) == 0) { infostream<<"Ignoring interaction from player "<getName() <<" because privileges are "<getMap().getNode(p_under); @@ -3011,31 +2992,29 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <m_removed) return; actionstream<getName()<<" punches object " - <punch(srp); + <getDescription()<getWieldedItem(); + ToolCapabilities toolcap = + punchitem.getToolCapabilities(m_itemdef); + v3f dir = (pointed_object->getBasePosition() - + (srp->getPosition() + srp->getEyeOffset()) + ).normalize(); + pointed_object->punch(dir, &toolcap, srp, + srp->m_time_from_last_punch); + srp->m_time_from_last_punch = 0; } } // action == 0 @@ -3053,459 +3032,61 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else if(action == 2) { // Only complete digging of nodes - if(pointed.type != POINTEDTHING_NODE) - return; - - // Mandatory parameter; actually used for nothing - core::map modified_blocks; - - content_t material = CONTENT_IGNORE; - u8 mineral = MINERAL_NONE; - - bool cannot_remove_node = !build_priv; - - MapNode n(CONTENT_IGNORE); - try + if(pointed.type == POINTEDTHING_NODE) { - n = m_env->getMap().getNode(p_under); - // Get mineral - mineral = n.getMineral(m_nodedef); - // Get material at position - material = n.getContent(); - // If not yet cancelled - if(cannot_remove_node == false) + MapNode n(CONTENT_IGNORE); + try { - // If it's not diggable, do nothing - if(m_nodedef->get(material).diggable == false) - { - infostream<<"Server: Not finishing digging: " - <<"Node not diggable" - <getMap().getNode(p_under); } - // If not yet cancelled - if(cannot_remove_node == false) + catch(InvalidPositionException &e) { - // Get node metadata - NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under); - if(meta && meta->nodeRemovalDisabled() == true) - { - infostream<<"Server: Not finishing digging: " - <<"Node metadata disables removal" - <getWieldedItem(); - /* - If node can't be removed, set block to be re-sent to - client and quit. - */ - if(cannot_remove_node) - { - infostream<<"Server: Not finishing digging."<SetBlockNotSent(blockpos); - - return; - } - - actionstream<getName()<<" digs "< far_players; - sendRemoveNode(p_under, peer_id, &far_players, 30); - - /* - Update and send inventory - */ + // 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(g_settings->getBool("creative_mode") == false) + if(pointed.type == POINTEDTHING_OBJECT) { - /* - Wear out tool - */ - 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"<addWear(prop.wear); - - if(weared_out) - { - mlist->deleteItem(item_i); - } - - srp->m_inventory_not_sent = true; - } - } + // Right click object - /* - Add dug item to inventory - */ + // Skip if object has been removed + if(pointed_object->m_removed) + return; - InventoryItem *item = NULL; + actionstream<getName()<<" right-clicks object " + <getDescription()<get(material).dug_item; - if(dug_s != "") - { - std::istringstream is(dug_s, std::ios::binary); - item = InventoryItem::deSerialize(is, this); - } - } - - if(item != NULL) - { - // Add a item to inventory - player->inventory.addItem("main", item); - srp->m_inventory_not_sent = true; - } - - item = NULL; - - if(mineral != MINERAL_NONE) - item = getDiggedMineralItem(mineral, this); - - // If not mineral - if(item == NULL) - { - const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item; - s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity; - 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); - } - } - - if(item != NULL) - { - // Add a item to inventory - player->inventory.addItem("main", item); - srp->m_inventory_not_sent = true; - } - } - - /* - Remove the node - (this takes some time so it is done after the quick stuff) - */ - { - MapEditEventIgnorer ign(&m_ignore_map_edit_events); - - m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks); - } - /* - Set blocks not sent to far players - */ - for(core::list::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_dignode(m_lua, p_under, n, srp); - } // action == 2 - - /* - 3: place block or right-click object - */ - else if(action == 3) - { - 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 "<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<getName()<<" places material " - <<(int)mitem->getMaterial() - <<" at "<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 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 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::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"<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"<getName()<<" places "<getName() - <<" at "<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; - } - } - } + // Do stuff + pointed_object->rightClick(srp); } - else if(pointed.type == POINTEDTHING_OBJECT) + else if(scriptapi_item_on_place(m_lua, + item, srp, pointed)) { - // Right click object + // Placement was handled in lua - if(!build_priv) - return; - - // Skip if object has been removed - if(pointed_object->m_removed) - return; - - actionstream<getName()<<" right-clicks object " - <rightClick(srp); + // Apply returned ItemStack + if(g_settings->getBool("creative_mode") == false) + srp->setWieldedItem(item); } } // action == 3 @@ -3515,38 +3096,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ else if(action == 4) { - InventoryList *ilist = player->inventory.getList("main"); - if(ilist == NULL) - return; + ItemStack item = srp->getWieldedItem(); - // 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"<getName()<<" uses "<getName() + actionstream<getName()<<" uses "<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 @@ -3559,9 +3119,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"WARNING: Server: Invalid action " <completeAddToInventoryLater(item_i); } else { @@ -3587,57 +3144,83 @@ void Server::onMapEditEvent(MapEditEvent *event) m_unsent_map_edit_queue.push_back(e); } -Inventory* Server::getInventory(InventoryContext *c, std::string id) +Inventory* Server::getInventory(const InventoryLocation &loc) { - if(id == "current_player") + switch(loc.type){ + case InventoryLocation::UNDEFINED: + {} + break; + case InventoryLocation::CURRENT_PLAYER: + {} + break; + case InventoryLocation::PLAYER: { - assert(c->current_player); - return &(c->current_player->inventory); + Player *player = m_env->getPlayer(loc.name.c_str()); + if(!player) + return NULL; + return &player->inventory; } - - Strfnd fn(id); - std::string id0 = fn.next(":"); - - if(id0 == "nodemeta") + break; + case InventoryLocation::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) - return meta->getInventory(); - infostream<<"nodemeta at ("<getMap().getNodeMetadata(loc.p); + if(!meta) + return NULL; + return meta->getInventory(); + } + break; + default: + assert(0); } - - infostream<<__FUNCTION_NAME<<": unknown id "<current_player); - ServerRemotePlayer *srp = - static_cast(c->current_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){ + case InventoryLocation::UNDEFINED: + {} + break; + case InventoryLocation::PLAYER: + { + ServerRemotePlayer *srp = static_cast + (m_env->getPlayer(loc.name.c_str())); + if(!srp) + return; srp->m_inventory_not_sent = true; - return; } - - Strfnd fn(id); - std::string id0 = fn.next(":"); - - if(id0 == "nodemeta") + break; + case InventoryLocation::NODEMETA: { - v3s16 p; - p.X = stoi(fn.next(",")); - p.Y = stoi(fn.next(",")); - p.Z = stoi(fn.next(",")); - v3s16 blockpos = getNodeBlockPos(p); + v3s16 blockpos = getNodeBlockPos(loc.p); - NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p); if(meta) meta->inventoryModified(); @@ -3646,11 +3229,11 @@ void Server::inventoryModified(InventoryContext *c, std::string id) block->raiseModified(MOD_STATE_WRITE_NEEDED); setBlockNotSent(blockpos); - - return; } - - infostream<<__FUNCTION_NAME<<": unknown id "< Server::getPlayerInfo() @@ -3698,7 +3281,7 @@ core::list Server::getPlayerInfo() void Server::peerAdded(con::Peer *peer) { DSTACK(__FUNCTION_NAME); - infostream<<"Server::peerAdded(): peer->id=" + verbosestream<<"Server::peerAdded(): peer->id=" <id<id=" + verbosestream<<"Server::deletingPeer(): peer->id=" <id<<", timeout="<serialize(tmp_os); - os<serialize(tmp_os); + std::ostringstream tmp_os2(std::ios::binary); + compressZlib(tmp_os.str(), tmp_os2); + os<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<peer_id); + os<getWieldedItem().getItemString()); // Make data buffer std::string s = os.str(); @@ -3924,8 +3476,10 @@ void Server::SendPlayerItems() for(i = players.begin(); i != players.end(); ++i) { Player *p = *i; + ServerRemotePlayer *srp = + static_cast(p); writeU16(os, p->peer_id); - os<getWieldedItem().getItemString()); } // Make data buffer @@ -3984,6 +3538,7 @@ void Server::BroadcastChatMessage(const std::wstring &message) void Server::SendPlayerHP(Player *player) { SendHP(m_con, player->peer_id, player->hp); + static_cast(player)->m_hp_not_sent = false; } void Server::SendMovePlayer(Player *player) @@ -4000,7 +3555,7 @@ void Server::SendMovePlayer(Player *player) v3f pos = player->getPosition(); f32 pitch = player->getPitch(); f32 yaw = player->getYaw(); - infostream<<"Server sending TOCLIENT_MOVE_PLAYER" + verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER" <<" pos=("< queue; @@ -4248,50 +3803,32 @@ void Server::SendBlocks(float dtime) } } -struct SendableTexture -{ - std::string name; - std::string path; - std::string data; - - SendableTexture(const std::string &name_="", const std::string path_="", - const std::string &data_=""): - name(name_), - path(path_), - data(data_) - {} -}; - -void Server::SendTextures(u16 peer_id) +void Server::PrepareTextures() { DSTACK(__FUNCTION_NAME); - infostream<<"Server::SendTextures(): Sending textures to client"< > texture_bunches; - texture_bunches.push_back(core::list()); - - u32 texture_size_bunch_total = 0; - core::list mods = getMods(m_modspaths); - for(core::list::Iterator i = mods.begin(); - i != mods.end(); i++){ - ModSpec mod = *i; + infostream<<"Server: Calculating texture checksums"<::Iterator i = m_mods.begin(); + i != m_mods.end(); i++){ + const ModSpec &mod = *i; std::string texturepath = mod.path + DIR_DELIM + "textures"; std::vector dirlist = fs::GetDirListing(texturepath); for(u32 j=0; j= bytes_per_bunch){ - texture_bunches.push_back(core::list()); - texture_size_bunch_total = 0; + this->m_Textures[tname] = TextureInformation(tpath,digest_string); + verbosestream<<"Server: sha1 for "< texture_announcements; + + for (std::map::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) { + + // Put in list + texture_announcements.push_back( + SendableTextureAnnouncement(i->first, i->second.sha1_digest)); + } + + //send announcements + + /* + u16 command + u32 number of textures + for each texture { + u16 length of name + string name + u16 length of digest string + string sha1_digest + } + */ + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES); + writeU16(os, texture_announcements.size()); + + for(core::list::Iterator + j = texture_announcements.begin(); + j != texture_announcements.end(); j++){ + os<name); + os<sha1_digest); + } + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8*)s.c_str(), s.size()); + + // Send as reliable + m_con.Send(peer_id, 0, data, true); + +} + +struct SendableTexture +{ + std::string name; + std::string path; + std::string data; + + SendableTexture(const std::string &name_="", const std::string path_="", + const std::string &data_=""): + name(name_), + path(path_), + data(data_) + {} +}; + +void Server::SendTexturesRequested(u16 peer_id,core::list tosend) { + DSTACK(__FUNCTION_NAME); + + verbosestream<<"Server::SendTexturesRequested(): " + <<"Sending textures to client"< > texture_bunches; + texture_bunches.push_back(core::list()); + + u32 texture_size_bunch_total = 0; + + for(core::list::Iterator i = tosend.begin(); i != tosend.end(); i++) { + if(m_Textures.find(i->name) == m_Textures.end()){ + errorstream<<"Server::SendTexturesRequested(): Client asked for " + <<"unknown texture \""<<(i->name)<<"\""<= bytes_per_bunch){ + texture_bunches.push_back(core::list()); + texture_size_bunch_total = 0; + } + } /* Create and send packets */ - - u32 num_bunches = texture_bunches.size(); - for(u32 i=0; i::Iterator + j = texture_bunches[i].begin(); + j != texture_bunches[i].end(); j++){ + os<name); + os<data); } - */ - std::ostringstream os(std::ios_base::binary); - writeU16(os, TOCLIENT_TEXTURES); - writeU16(os, num_bunches); - writeU16(os, i); - writeU32(os, texture_bunches[i].size()); - - for(core::list::Iterator - j = texture_bunches[i].begin(); - j != texture_bunches[i].end(); j++){ - os<name); - os<data); + // Make data buffer + std::string s = os.str(); + verbosestream<<"Server::SendTexturesRequested(): bunch " + <getName()<<" dies"<hp > damage) - { - player->hp -= damage; - SendPlayerHP(player); + srp->setHP(0); + + // Trigger scripted stuff + scriptapi_on_dieplayer(m_lua, srp); + + // Handle players that are not connected + if(player->peer_id == PEER_ID_INEXISTENT){ + RespawnPlayer(player); + return; } - else - { - infostream<<"Server::HandlePlayerHP(): Player " - <getName()<<" dies"<hp = 0; - - //TODO: Throw items around - - // Handle players that are not connected - if(player->peer_id == PEER_ID_INEXISTENT){ - RespawnPlayer(player); - return; - } - SendPlayerHP(player); - - RemoteClient *client = getClient(player->peer_id); - if(client->net_proto_version >= 3) - { - SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0)); - srp->m_removed = true; - srp->m_respawn_active = true; - } - else - { - RespawnPlayer(player); - } - } + SendPlayerHP(player); + SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0)); } void Server::RespawnPlayer(Player *player) { - player->hp = 20; ServerRemotePlayer *srp = static_cast(player); + srp->setHP(20); bool repositioned = scriptapi_on_respawnplayer(m_lua, srp); if(!repositioned){ v3f pos = findSpawnPos(m_env->getServerMap()); @@ -4439,63 +4106,18 @@ void Server::UpdateCrafting(u16 peer_id) Player* player = m_env->getPlayer(peer_id); assert(player); - ServerRemotePlayer *srp = static_cast(player); + // Get a preview for crafting + ItemStack preview; // 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) - { - // 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 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()); - } - 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); - } + if(g_settings->getBool("creative_mode") == false) + getCraftingResult(&player->inventory, preview, false, this); + + // Put the new preview in + InventoryList *plist = player->inventory.getList("craftpreview"); + assert(plist); + assert(plist->getSize() >= 1); + plist->changeItem(0, preview); } RemoteClient* Server::getClient(u16 peer_id) @@ -4564,8 +4186,8 @@ void Server::setPlayerPassword(const std::string &name, const std::wstring &pass // Saves g_settings to configpath given at initialization void Server::saveConfig() { - if(m_configpath != "") - g_settings->updateConfigFile(m_configpath.c_str()); + if(m_path_config != "") + g_settings->updateConfigFile(m_path_config.c_str()); } void Server::notifyPlayer(const char *name, const std::wstring msg) @@ -4591,9 +4213,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() { @@ -4603,10 +4225,6 @@ ICraftDefManager* Server::getCraftDefManager() { return m_craftdef; } -ICraftItemDefManager* Server::getCraftItemDefManager() -{ - return m_craftitemdef; -} ITextureSource* Server::getTextureSource() { return NULL; @@ -4616,9 +4234,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() { @@ -4628,9 +4246,16 @@ IWritableCraftDefManager* Server::getWritableCraftDefManager() { return m_craftdef; } -IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager() + +const ModSpec* Server::getModSpec(const std::string &modname) { - return m_craftitemdef; + for(core::list::Iterator i = m_mods.begin(); + i != m_mods.end(); i++){ + const ModSpec &mod = *i; + if(mod.name == modname) + return &mod; + } + return NULL; } v3f findSpawnPos(ServerMap &map) @@ -4715,15 +4340,24 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id) // Got one. player->peer_id = peer_id; + // Re-add player to environment + if(player->m_removed) + { + player->m_removed = false; + player->setId(0); + m_env->addActiveObject(player); + } + // Reset inventory to creative if in creative mode if(g_settings->getBool("creative_mode")) { // 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 - craft_set_creative_inventory(player, this); + player->resetInventory(); + scriptapi_get_creative_inventory(m_lua, player); } return player; @@ -4751,12 +4385,13 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id) v3f pos = findSpawnPos(m_env->getServerMap()); player = new ServerRemotePlayer(m_env, pos, peer_id, name); + ServerRemotePlayer *srp = static_cast(player); /* Add player to environment */ m_env->addPlayer(player); + m_env->addActiveObject(srp); /* Run scripts */ - ServerRemotePlayer *srp = static_cast(player); scriptapi_on_newplayer(m_lua, srp); /* Add stuff to inventory */ @@ -4764,10 +4399,11 @@ 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 - craft_set_creative_inventory(player, this); + player->resetInventory(); + scriptapi_get_creative_inventory(m_lua, player); } return player; @@ -4890,7 +4526,8 @@ void Server::handlePeerChange(PeerChange &c) //SendPlayerInfos(); // Send leave chat message to all remaining clients - BroadcastChatMessage(message); + if(message.length() != 0) + BroadcastChatMessage(message); } // PEER_REMOVED else @@ -4905,7 +4542,7 @@ void Server::handlePeerChanges() { PeerChange c = m_peer_change_queue.pop_front(); - infostream<<"Server: Handling peer change: " + verbosestream<<"Server: Handling peer change: " <<"id="<getFloat("dedicated_server_step"); // This is kind of a hack but can be done like this // because server.step() is very light { ScopeProfiler sp(g_profiler, "dedicated server sleep"); - sleep_ms(30); + sleep_ms((int)(steplen*1000.0)); } - server.step(0.030); + server.step(steplen); if(server.getShutdownRequested() || kill) { - infostream<getFloat("profiler_print_interval"); if(profiler_print_interval != 0) { - if(m_profiler_interval.step(0.030, profiler_print_interval)) + if(m_profiler_interval.step(steplen, profiler_print_interval)) { infostream<<"Profiler:"<print(infostream); g_profiler->clear(); } } - - /* - Player info - */ - static int counter = 0; - counter--; - if(counter <= 0) - { - counter = 10; - - core::list list = server.getPlayerInfo(); - core::list::Iterator i; - static u32 sum_old = 0; - u32 sum = PIChecksum(list); - if(sum != sum_old) - { - infostream<PrintLine(&infostream); - } - } - sum_old = sum; - } } }