X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fserver.cpp;h=e3747775a22ae91c0a6295a855da12b8854a6602;hb=ecd5c5f9206437c320da029680cf1d053b644761;hp=d47dcb9ce1ad9cd46e17cbfda3b187c40bedd2f1;hpb=9c72d44fe75cc448cc0da1191a36fe6a7d879f20;p=oweals%2Fminetest.git diff --git a/src/server.cpp b/src/server.cpp index d47dcb9ce..e3747775a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -29,9 +29,41 @@ with this program; if not, write to the Free Software Foundation, Inc., #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" #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) +class MapEditEventIgnorer +{ +public: + MapEditEventIgnorer(bool *flag): + m_flag(flag) + { + if(*m_flag == false) + *m_flag = true; + else + m_flag = NULL; + } + + ~MapEditEventIgnorer() + { + if(m_flag) + { + assert(*m_flag); + *m_flag = false; + } + } + +private: + bool *m_flag; +}; + void * ServerThread::Thread() { ThreadStarted(); @@ -73,10 +105,10 @@ void * EmergeThread::Thread() DSTACK(__FUNCTION_NAME); - //bool debug=false; - BEGIN_DEBUG_EXCEPTION_HANDLER + bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info"); + /* Get block info from queue, emerge them and send them to clients. @@ -123,7 +155,7 @@ void * EmergeThread::Thread() Also decrement the emerge queue count in clients. */ - bool optional = true; + bool only_from_disk = true; { core::map::Iterator i; @@ -134,55 +166,25 @@ void * EmergeThread::Thread() // Check flags u8 flags = i.getNode()->getValue(); if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false) - optional = false; + only_from_disk = false; } } - - /*dstream<<"EmergeThread: p=" - <<"("<isGenerated() == false) + { + if(enable_mapgen_debug_info) + dstream<<"EmergeThread: generating"<m_ignore_map_edit_events); + + // Activate objects and stuff + m_server->m_env.activateBlock(block, 3600); } } else { - if(block->getLightingExpired()){ + /*if(block->getLightingExpired()){ lighting_invalidated_blocks[block->getPos()] = block; - } + }*/ } // TODO: Some additional checking and lighting updating, - // see emergeBlock + // see emergeBlock } {//envlock @@ -232,7 +264,8 @@ void * EmergeThread::Thread() Collect a list of blocks that have been modified in addition to the fetched one. */ - + +#if 0 if(lighting_invalidated_blocks.size() > 0) { /*dstream<<"lighting "<getValue(); modified_blocks.insert(block->getPos(), block); } +#endif } // If we got no block, there should be no invalidated blocks else { - assert(lighting_invalidated_blocks.size() == 0); + //assert(lighting_invalidated_blocks.size() == 0); } }//envlock @@ -310,11 +344,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/ // Increment timers - m_nearest_unsent_reset_timer += dtime; m_nothing_to_send_pause_timer -= dtime; if(m_nothing_to_send_pause_timer >= 0) + { + // Keep this reset + m_nearest_unsent_reset_timer = 0; return; + } // Won't send anything if already sending if(m_blocks_sending.size() >= g_settings.getU16 @@ -324,24 +361,33 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, return; } + //TimeTaker timer("RemoteClient::GetNextBlocks"); + Player *player = server->m_env.getPlayer(peer_id); assert(player != NULL); v3f playerpos = player->getPosition(); v3f playerspeed = player->getSpeed(); + v3f playerspeeddir(0,0,0); + if(playerspeed.getLength() > 1.0*BS) + playerspeeddir = playerspeed / playerspeed.getLength(); + // Predict to next block + v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS; - v3s16 center_nodepos = floatToInt(playerpos, BS); + v3s16 center_nodepos = floatToInt(playerpos_predicted, BS); v3s16 center = getNodeBlockPos(center_nodepos); // Camera position and direction - v3f camera_pos = - playerpos + v3f(0, BS+BS/2, 0); + v3f camera_pos = player->getEyePosition(); v3f camera_dir = v3f(0,0,1); camera_dir.rotateYZBy(player->getPitch()); camera_dir.rotateXZBy(player->getYaw()); + /*dstream<<"camera_dir=("<getPlayerName(peer_id)< d_start+1) + d_max = d_start+1; + /*if(d_max_gen > d_start+2) + d_max_gen = d_start+2;*/ + //dstream<<"Starting from "<= 3) + if((s16)m_nothing_to_send_counter >= + g_settings.getS16("max_block_send_distance")) { // Pause time in seconds - m_nothing_to_send_pause_timer = 2.0; + m_nothing_to_send_pause_timer = 1.0; + /*dstream<<"nothing to send to " + <getPlayerName(peer_id) + <<" (d="<stepObjects(dtime, true, server->getDayNightRatio()); + block->stepObjects(dtime, true, server->m_env.getDayNightRatio()); stepped_blocks.insert(p, true); block->setChangedFlag(); } @@ -815,7 +909,9 @@ void RemoteClient::SendObjectData( bos.write((char*)buf, 6); // Write objects - block->serializeObjects(bos, serialization_version); + //block->serializeObjects(bos, serialization_version); // DEPRECATED + // count=0 + writeU16(bos, 0); blockcount++; @@ -961,17 +1057,19 @@ u32 PIChecksum(core::list &l) */ Server::Server( - std::string mapsavedir + std::string mapsavedir, + std::string configpath ): m_env(new ServerMap(mapsavedir), this), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), + m_authmanager(mapsavedir+"/auth.txt"), m_thread(this), m_emergethread(this), - m_time_of_day(9000), m_time_counter(0), m_time_of_day_send_timer(0), m_uptime(0), m_mapsavedir(mapsavedir), + m_configpath(configpath), m_shutdown_requested(false), m_ignore_map_edit_events(false), m_ignore_map_edit_events_peer_id(0) @@ -986,10 +1084,19 @@ Server::Server( m_con_mutex.Init(); m_step_dtime_mutex.Init(); m_step_dtime = 0.0; - + + // Register us to receive map edit events m_env.getMap().addEventReceiver(this); + // If file exists, load environment metadata + if(fs::PathExists(m_mapsavedir+"/env_meta.txt")) + { + dstream<<"Server: Loading environment metadata"< modified_blocks; m_env.getMap().transformLiquids(modified_blocks); #if 0 @@ -1278,10 +1412,11 @@ void Server::AsyncRunStep() */ { //dstream<<"Server: Checking added and deleted active objects"<peer_id); if(player==NULL) { - dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "<peer_id - <<" has no associated player"<peer_id + <<" has no associated player"<getPosition(), BS); @@ -1426,6 +1563,8 @@ void Server::AsyncRunStep() JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); + ScopeProfiler sp(&g_profiler, "Server: sending object messages"); + // Key = object id // Value = data sent by object core::map* > buffered_messages; @@ -1538,33 +1677,113 @@ void Server::AsyncRunStep() Send queued-for-sending map edit events. */ { + // Don't send too many at a time + //u32 count = 0; + + // Single change sending is disabled if queue size is not small + bool disable_single_change_sending = false; + if(m_unsent_map_edit_queue.size() >= 4) + disable_single_change_sending = true; + + bool got_any_events = false; + + // 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. + // Instead of sending the changes, MapBlocks are set not sent + // for them. + core::list far_players; if(event->type == MEET_ADDNODE) { - dstream<<"Server: MEET_ADDNODE"<p, event->n, event->already_known_by_peer); + //dstream<<"Server: MEET_ADDNODE"<p, event->n, event->already_known_by_peer, + &far_players, 5); + else + sendAddNode(event->p, event->n, event->already_known_by_peer, + &far_players, 30); } else if(event->type == MEET_REMOVENODE) { - dstream<<"Server: MEET_REMOVENODE"<p, event->already_known_by_peer); + //dstream<<"Server: MEET_REMOVENODE"<p, event->already_known_by_peer, + &far_players, 5); + else + sendRemoveNode(event->p, event->already_known_by_peer, + &far_players, 30); + } + else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED) + { + dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<p); } else if(event->type == MEET_OTHER) { + prof.add("MEET_OTHER", 1); dstream<<"WARNING: Server: MEET_OTHER not implemented" <type)< 0) + { + // Convert list format to that wanted by SetBlocksNotSent + core::map modified_blocks2; + for(core::map::Iterator + i = event->modified_blocks.getIterator(); + i.atEnd()==false; i++) + { + v3s16 p = i.getNode()->getKey(); + modified_blocks2.insert(p, + m_env.getMap().getBlockNoCreateNoEx(p)); + } + // Set blocks not sent + 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_blocks2); + } + } delete event; + + /*// Don't send too many at a time + count++; + if(count >= 1 && m_unsent_map_edit_queue.size() < 100) + break;*/ + } + + if(got_any_events) + { + dstream<<"Server: MapEditEvents:"< changed_blocks; - m_env.getMap().nodeMetadataStep(dtime, changed_blocks); - - for(core::map::Iterator - i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd()==false; i++) - { - RemoteClient *client = i.getNode()->getValue(); - client->SetBlockNotSent(block->getPos()); - } - } - } - /* Trigger emergethread (it somehow gets to a non-triggered but bysy state sometimes) @@ -1627,7 +1821,7 @@ void Server::AsyncRunStep() } } - // Save map + // Save map, players and auth stuff { float &counter = m_savemap_timer; counter += dtime; @@ -1635,25 +1829,37 @@ void Server::AsyncRunStep() { counter = 0.0; + ScopeProfiler sp(&g_profiler, "Server: saving stuff"); + + // Auth stuff + if(m_authmanager.isModified()) + m_authmanager.save(); + + // Map JMutexAutoLock lock(m_env_mutex); - if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true) - { - // Save only changed parts - m_env.getMap().save(true); + /*// Unload unused data (delete from memory) + m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + */ + /*u32 deleted_count = m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + */ - // Delete unused sectors - u32 deleted_count = m_env.getMap().deleteUnusedSectors( - g_settings.getFloat("server_unload_unused_sectors_timeout")); - if(deleted_count > 0) - { - dout_server<<"Server: Unloaded "< 0) + { + dout_server<<"Server: Unloaded "<= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2) + { + net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]); + } + + getClient(peer->id)->net_proto_version = net_proto_version; + + if(net_proto_version == 0) + { + SendAccessDenied(m_con, peer_id, + L"Your client is too old. Please upgrade."); return; } @@ -1766,17 +1994,82 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ // Get player name - const u32 playername_size = 20; - char playername[playername_size]; - for(u32 i=0; igetPosition()+v3f(0,BS/2,0), BS)); - //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed()); - writeU64(&reply[2+1+6], 0); // no seed + writeU64(&reply[2+1+6], m_env.getServerMap().getSeed()); // Send as reliable m_con.Send(peer_id, 0, reply, true); @@ -1874,7 +2166,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send time of day { SharedBuffer data = makePacket_TOCLIENT_TIME_OF_DAY( - m_time_of_day.get()); + m_env.getTimeOfDay()); m_con.Send(peer->id, 0, data, true); } @@ -1894,6 +2186,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) message += L" joined game"; BroadcastChatMessage(message); } + + // Warnings about protocol version can be issued here + /*if(getClient(peer->id)->net_proto_version == 0) + { + SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER"); + }*/ return; } @@ -1994,6 +2292,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 13) return; + if((getPlayerPrivs(player) & PRIV_BUILD) == 0) + return; + /* [0] u16 command [2] u8 button (0=left, 1=right) @@ -2075,6 +2376,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 7) return; + if((getPlayerPrivs(player) & PRIV_BUILD) == 0) + return; + /* length: 7 [0] u16 command @@ -2095,71 +2399,92 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } + // Skip if object has been removed + if(obj->m_removed) + return; + //TODO: Check that object is reasonably close // Left click, pick object up (usually) if(button == 0) { - InventoryList *ilist = player->inventory.getList("main"); - if(g_settings.getBool("creative_mode") == false && ilist != NULL) - { + /* + Try creating inventory item + */ + InventoryItem *item = obj->createPickedUpItem(); - // Skip if inventory has no free space - if(ilist->getUsedSlots() == ilist->getSize()) + if(item) + { + InventoryList *ilist = player->inventory.getList("main"); + if(ilist != NULL) { - dout_server<<"Player inventory has no free space"<getUsedSlots() == ilist->getSize()) + { + dout_server<<"Player inventory has no free space"<m_removed) - return; - - /* - Create the inventory item - */ - InventoryItem *item = obj->createPickedUpItem(); - - if(item) - { - // Add to inventory and send inventory - ilist->addItem(item); - UpdateCrafting(player->peer_id); - SendInventory(player->peer_id); + // Add to inventory and send inventory + ilist->addItem(item); + UpdateCrafting(player->peer_id); + SendInventory(player->peer_id); + } // Remove object from environment obj->m_removed = true; } - else - { - /* - Item cannot be picked up. Punch it instead. - */ + } + else + { + /* + Item cannot be picked up. Punch it instead. + */ - ToolItem *titem = NULL; - std::string toolname = ""; + ToolItem *titem = NULL; + std::string toolname = ""; - InventoryList *mlist = player->inventory.getList("main"); - if(mlist != NULL) - { - InventoryItem *item = mlist->getItem(item_i); - if(item && (std::string)item->getName() == "ToolItem") - { - titem = (ToolItem*)item; - toolname = titem->getToolName(); - } - } - - u16 wear = obj->punch(toolname); - - if(titem) + InventoryList *mlist = player->inventory.getList("main"); + if(mlist != NULL) + { + InventoryItem *item = mlist->getItem(item_i); + if(item && (std::string)item->getName() == "ToolItem") { - bool weared_out = titem->addWear(wear); - if(weared_out) - mlist->deleteItem(item_i); - SendInventory(player->peer_id); + titem = (ToolItem*)item; + toolname = titem->getToolName(); } } + + v3f playerpos = player->getPosition(); + v3f objpos = obj->getBasePosition(); + v3f dir = (objpos - playerpos).normalize(); + + u16 wear = obj->punch(toolname, dir); + + if(titem) + { + bool weared_out = titem->addWear(wear); + if(weared_out) + mlist->deleteItem(item_i); + SendInventory(player->peer_id); + } + } + } + // Right click, do something with object + if(button == 1) + { + // Track hp changes super-crappily + u16 oldhp = player->hp; + + // Do stuff + obj->rightClick(player); + + // Send back stuff + if(player->hp != oldhp) + { + SendPlayerHP(player); } } } @@ -2224,7 +2549,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Mandatory parameter; actually used for nothing core::map modified_blocks; - u8 material; + content_t material = CONTENT_IGNORE; u8 mineral = MINERAL_NONE; bool cannot_remove_node = false; @@ -2235,7 +2560,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Get mineral mineral = n.getMineral(); // Get material at position - material = n.d; + material = n.getContent(); // If not yet cancelled if(cannot_remove_node == false) { @@ -2272,6 +2597,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) cannot_remove_node = true; } + // Make sure the player is allowed to do it + if((getPlayerPrivs(player) & PRIV_BUILD) == 0) + { + dstream<<"Player "<getName()<<" cannot remove node" + <<" because privileges are "< far_players; - sendRemoveNode(p_under, peer_id, &far_players, 100); + sendRemoveNode(p_under, peer_id, &far_players, 30); /* Update and send inventory @@ -2374,10 +2708,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) Remove the node (this takes some time so it is done after the quick stuff) */ - m_ignore_map_edit_events = true; - m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); - m_ignore_map_edit_events = false; - + { + MapEditEventIgnorer ign(&m_ignore_map_edit_events); + + m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + } /* Set blocks not sent to far players */ @@ -2418,7 +2753,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) try{ // Don't add a node if this is not a free space MapNode n2 = m_env.getMap().getNode(p_over); - if(content_buildable_to(n2.d) == false) + bool no_enough_privs = + ((getPlayerPrivs(player) & PRIV_BUILD)==0); + if(no_enough_privs) + dstream<<"Player "<getName()<<" cannot add node" + <<" because privileges are "<getMaterial(); - if(content_features(n.d).wall_mounted) - n.dir = packDir(p_under - p_over); - + n.setContent(mitem->getMaterial()); + + // Calculate direction for wall mounted stuff + if(content_features(n).wall_mounted) + n.param2 = packDir(p_under - p_over); + + // Calculate the direction for furnaces and chests and stuff + if(content_features(n).param_type == CPT_FACEDIR_SIMPLE) + { + v3f playerpos = player->getPosition(); + v3f blockpos = intToFloat(p_over, 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 players + Send to all close-by players */ core::list far_players; - sendAddNode(p_over, n, 0, &far_players, 100); + sendAddNode(p_over, n, 0, &far_players, 30); /* Handle inventory @@ -2480,10 +2845,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) This takes some time so it is done after the quick stuff */ core::map modified_blocks; - m_ignore_map_edit_events = true; - m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); - m_ignore_map_edit_events = false; - + { + MapEditEventIgnorer ign(&m_ignore_map_edit_events); + + m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); + } /* Set blocks not sent to far players */ @@ -2615,6 +2981,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) #endif else if(command == TOSERVER_SIGNTEXT) { + if((getPlayerPrivs(player) & PRIV_BUILD) == 0) + return; /* u16 command v3s16 blockpos @@ -2672,6 +3040,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } else if(command == TOSERVER_SIGNNODETEXT) { + if((getPlayerPrivs(player) & PRIV_BUILD) == 0) + return; /* u16 command v3s16 p @@ -2846,6 +3216,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Whether to send to other players bool send_to_others = false; + // Local player gets all privileges regardless of + // what's set on their account. + u64 privs = getPlayerPrivs(player); + // Parse commands std::wstring commandprefix = L"/#"; if(message.substr(0, commandprefix.size()) == commandprefix) @@ -2853,82 +3227,41 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) line += L"Server: "; message = message.substr(commandprefix.size()); - // Get player name as narrow string - std::string name_s = player->getName(); - // Convert message to narrow string - std::string message_s = wide_to_narrow(message); - // Operator is the single name defined in config. - std::string operator_name = g_settings.get("name"); - bool is_operator = (operator_name != "" && - wide_to_narrow(name) == operator_name); - bool valid_command = false; - if(message_s == "help") - { - line += L"-!- Available commands: "; - line += L"status "; - if(is_operator) - { - line += L"shutdown setting time "; - } - else - { - } - send_to_sender = true; - valid_command = true; - } - else if(message_s == "status") - { - line = getStatusString(); - send_to_sender = true; - valid_command = true; - } - else if(is_operator) + + WStrfnd f1(message); + f1.next(L" "); // Skip over /#whatever + std::wstring paramstring = f1.next(L""); + + ServerCommandContext *ctx = new ServerCommandContext( + str_split(message, L' '), + paramstring, + this, + &m_env, + player, + privs); + + line += processServerCommand(ctx); + send_to_sender = ctx->flags & 1; + send_to_others = ctx->flags & 2; + delete ctx; + + } + else + { + if(privs & PRIV_SHOUT) { - if(message_s == "shutdown") - { - dstream< "; + line += message; + send_to_others = true; } - - if(valid_command == false) + else { - line += L"-!- Invalid command: " + message; + line += L"Server: You are not allowed to shout"; send_to_sender = true; } } - else - { - line += L"<"; - /*if(is_operator) - line += L"@";*/ - line += name; - line += L"> "; - line += message; - send_to_others = true; - } if(line != L"") { @@ -2988,6 +3321,74 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) SendPlayerHP(player); } + else if(command == TOSERVER_PASSWORD) + { + /* + [0] u16 TOSERVER_PASSWORD + [2] u8[28] old password + [30] u8[28] new password + */ + + if(datasize != 2+PASSWORD_SIZE*2) + return; + /*char password[PASSWORD_SIZE]; + for(u32 i=0; igetName(); + + if(m_authmanager.exists(playername) == false) + { + dstream<<"Server: playername not found in authmanager"<wieldItem(item); + } else { derr_server<<"WARNING: Server::ProcessData(): Ignoring " @@ -3005,7 +3406,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) void Server::onMapEditEvent(MapEditEvent *event) { - dstream<<"Server::onMapEditEvent()"<clone(); @@ -3168,6 +3569,22 @@ void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp) con.Send(peer_id, 0, data, true); } +void Server::SendAccessDenied(con::Connection &con, u16 peer_id, + const std::wstring &reason) +{ + DSTACK(__FUNCTION_NAME); + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_ACCESS_DENIED); + os< data((u8*)s.c_str(), s.size()); + // Send as reliable + con.Send(peer_id, 0, data, true); +} + /* Non-static send methods */ @@ -3434,6 +3851,17 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id, } } +void Server::setBlockNotSent(v3s16 p) +{ + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd()==false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + client->SetBlockNotSent(p); + } +} + void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver) { DSTACK(__FUNCTION_NAME); @@ -3499,20 +3927,24 @@ void Server::SendBlocks(float dtime) core::array queue; s32 total_sending = 0; - - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) + { - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); + ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending"); - total_sending += client->SendingCount(); - - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; - - client->GetNextBlocks(this, dtime, queue); + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + + total_sending += client->SendingCount(); + + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + + client->GetNextBlocks(this, dtime, queue); + } } // Sort. @@ -3583,317 +4015,10 @@ void Server::UpdateCrafting(u16 peer_id) items[i] = clist->getItem(i); } - bool found = false; - - // Wood - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new MaterialItem(CONTENT_WOOD, 4)); - found = true; - } - } - - // Stick - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new CraftItem("Stick", 4)); - found = true; - } - } - - // Sign - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - //rlist->addItem(new MapBlockObjectItem("Sign")); - rlist->addItem(new MaterialItem(CONTENT_SIGN_WALL, 1)); - found = true; - } - } - - // Torch - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal"); - specs[3] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new MaterialItem(CONTENT_TORCH, 4)); - found = true; - } - } - - // Wooden pick - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("WPick", 0)); - found = true; - } - } - - // Stone pick - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("STPick", 0)); - found = true; - } - } - - // Steel pick - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("SteelPick", 0)); - found = true; - } - } - - // Mese pick - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE); - specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("MesePick", 0)); - found = true; - } - } - - // Wooden shovel - if(!found) - { - ItemSpec specs[9]; - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("WShovel", 0)); - found = true; - } - } - - // Stone shovel - if(!found) - { - ItemSpec specs[9]; - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("STShovel", 0)); - found = true; - } - } - - // Steel shovel - if(!found) - { - ItemSpec specs[9]; - specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("SteelShovel", 0)); - found = true; - } - } - - // Wooden axe - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("WAxe", 0)); - found = true; - } - } - - // Stone axe - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("STAxe", 0)); - found = true; - } - } - - // Steel axe - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("SteelAxe", 0)); - found = true; - } - } - - // Wooden sword - if(!found) - { - ItemSpec specs[9]; - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("WSword", 0)); - found = true; - } - } - - // Stone sword - if(!found) - { - ItemSpec specs[9]; - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("STSword", 0)); - found = true; - } - } - - // Steel sword - if(!found) - { - ItemSpec specs[9]; - specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new ToolItem("SteelSword", 0)); - found = true; - } - } - - // Chest - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new MaterialItem(CONTENT_CHEST, 1)); - found = true; - } - } - - // Furnace - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new MaterialItem(CONTENT_FURNACE, 1)); - found = true; - } - } - - // Steel block - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot"); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new MaterialItem(CONTENT_STEEL, 1)); - found = true; - } - } + // Get result of crafting grid + InventoryItem *result = craft_get_result(items); + if(result) + rlist->addItem(result); } } // if creative_mode == false @@ -3940,106 +4065,25 @@ std::wstring Server::getStatusString() } os<isSavingEnabled() == false) - os<<" WARNING: Map saving is disabled."<resetInventory(); - - // Give some good tools - { - InventoryItem *item = new ToolItem("MesePick", 0); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("SteelPick", 0); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("SteelAxe", 0); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("SteelShovel", 0); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - - /* - Give materials - */ - - // CONTENT_IGNORE-terminated list - u8 material_items[] = { - CONTENT_TORCH, - CONTENT_COBBLE, - CONTENT_MUD, - CONTENT_STONE, - CONTENT_SAND, - CONTENT_TREE, - CONTENT_LEAVES, - CONTENT_MESE, - CONTENT_WATERSOURCE, - CONTENT_CLOUD, - CONTENT_CHEST, - CONTENT_FURNACE, - CONTENT_SIGN_WALL, - CONTENT_IGNORE - }; - - u8 *mip = material_items; - for(u16 i=0; iinventory.addItem("main", item); - - mip++; - } - -#if 0 - assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE); - - // add torch first - InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1); - player->inventory.addItem("main", item); - - // Then others - for(u16 i=0; iinventory.addItem("main", item); - } -#endif - - /*// Sign - { - InventoryItem *item = new MapBlockObjectItem("Sign Example text"); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - }*/ -} - v3f findSpawnPos(ServerMap &map) { //return v3f(50,50,50)*BS; - + v2s16 nodepos; s16 groundheight = 0; +#if 0 + nodepos = v2s16(0,0); + groundheight = 20; +#endif + +#if 1 // Try to find a good place a few times for(s32 i=0; i<1000; i++) { @@ -4069,6 +4113,7 @@ v3f findSpawnPos(ServerMap &map) //dstream<<"Searched through "<inventory_backup = new Inventory(); + *(player->inventory_backup) = player->inventory; + // Set creative inventory + craft_set_creative_inventory(player); } return player; @@ -4128,6 +4177,10 @@ Player *Server::emergePlayer(const char *name, const char *password, //player->peer_id = PEER_ID_INEXISTENT; player->peer_id = peer_id; player->updateName(name); + m_authmanager.add(name); + m_authmanager.setPassword(name, password); + m_authmanager.setPrivs(name, + stringToPrivs(g_settings.get("default_privs"))); /* Set player position @@ -4152,78 +4205,16 @@ Player *Server::emergePlayer(const char *name, const char *password, if(g_settings.getBool("creative_mode")) { - setCreativeInventory(player); + // Warning: double code above + // Backup actual inventory + player->inventory_backup = new Inventory(); + *(player->inventory_backup) = player->inventory; + // Set creative inventory + craft_set_creative_inventory(player); } else if(g_settings.getBool("give_initial_stuff")) { - { - InventoryItem *item = new ToolItem("SteelPick", 0); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new MaterialItem(CONTENT_TORCH, 99); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("SteelAxe", 0); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("SteelShovel", 0); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new MaterialItem(CONTENT_COBBLE, 99); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - /*{ - InventoryItem *item = new MaterialItem(CONTENT_MESE, 6); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new CraftItem("Stick", 4); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("WPick", 32000); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("STPick", 32000); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - }*/ - /*// and some signs - for(u16 i=0; i<4; i++) - { - InventoryItem *item = new MapBlockObjectItem("Sign Example text"); - bool r = player->inventory.addItem("main", item); - assert(r == true); - }*/ - /*// Give some other stuff - { - InventoryItem *item = new MaterialItem(CONTENT_TREE, 999); - bool r = player->inventory.addItem("main", item); - assert(r == true); - }*/ + craft_give_initial_stuff(player); } return player; @@ -4341,29 +4332,69 @@ void Server::handlePeerChanges() } } +u64 Server::getPlayerPrivs(Player *player) +{ + if(player==NULL) + return 0; + std::string playername = player->getName(); + // Local player gets all privileges regardless of + // what's set on their account. + if(g_settings.get("name") == playername) + { + return PRIV_ALL; + } + else + { + return getPlayerAuthPrivs(playername); + } +} + void dedicated_server_loop(Server &server, bool &kill) { DSTACK(__FUNCTION_NAME); - std::cout<PrintLine(&std::cout); + i->PrintLine(&dstream); } } sum_old = sum;