]> git.lizzy.rs Git - minetest.git/blobdiff - src/server.cpp
Revert old 4BS/s walk speed for now
[minetest.git] / src / server.cpp
index 69f655e6acd7b244a2bc4a7cdd62dca0f8d96281..2139df957388a8b05740cdaf4440374541fdf9ec 100644 (file)
@@ -48,6 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "sha1.h"
 #include "base64.h"
 #include "tool.h"
+#include "utility_string.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -108,6 +109,10 @@ void * ServerThread::Thread()
                {
                        infostream<<"Server: PeerNotFoundException"<<std::endl;
                }
+               catch(con::ConnectionBindFailed &e)
+               {
+                       m_server->setAsyncFatalError(e.what());
+               }
        }
        
        END_DEBUG_EXCEPTION_HANDLER(errorstream)
@@ -824,32 +829,21 @@ void PlayerInfo::PrintLine(std::ostream *s)
        (*s)<<std::endl;
 }
 
-u32 PIChecksum(core::list<PlayerInfo> &l)
-{
-       core::list<PlayerInfo>::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;
-}
-
 /*
        Server
 */
 
 Server::Server(
-               std::string path_world,
-               std::string path_config,
-               std::string gamename
+               const std::string &path_world,
+               const std::string &path_config,
+               const SubgameSpec &gamespec,
+               bool simple_singleplayer_mode
        ):
-       m_gamename(gamename),
        m_path_world(path_world),
        m_path_config(path_config),
+       m_gamespec(gamespec),
+       m_simple_singleplayer_mode(simple_singleplayer_mode),
+       m_async_fatal_error(""),
        m_env(NULL),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
        m_authmanager(path_world+DIR_DELIM+"auth.txt"),
@@ -867,11 +861,6 @@ Server::Server(
        m_ignore_map_edit_events(false),
        m_ignore_map_edit_events_peer_id(0)
 {
-       infostream<<"Server created."<<std::endl;
-       infostream<<"- path_world  = "<<path_world<<std::endl;
-       infostream<<"- path_config = "<<path_config<<std::endl;
-       infostream<<"- gamename    = "<<gamename<<std::endl;
-
        m_liquid_transform_timer = 0.0;
        m_print_info_timer = 0.0;
        m_objectdata_timer = 0.0;
@@ -883,58 +872,88 @@ Server::Server(
        m_step_dtime_mutex.Init();
        m_step_dtime = 0.0;
 
+       if(path_world == "")
+               throw ServerError("Supplied empty world path");
+       
+       if(!gamespec.isValid())
+               throw ServerError("Supplied invalid gamespec");
+       
        // Figure out some paths
+       // share/server
        m_path_share = porting::path_share + DIR_DELIM + "server";
-       m_path_game = m_path_share + DIR_DELIM + "games" + DIR_DELIM + m_gamename;
+
+       infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
+       if(m_simple_singleplayer_mode)
+               infostream<<" in simple singleplayer mode"<<std::endl;
+       else
+               infostream<<std::endl;
+       infostream<<"- world:  "<<m_path_world<<std::endl;
+       infostream<<"- config: "<<m_path_config<<std::endl;
+       infostream<<"- game:   "<<m_gamespec.path<<std::endl;
+       for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
+                       i != m_gamespec.addon_paths.end(); i++)
+               infostream<<"- addons: "<<(*i)<<std::endl;
 
        // Path to builtin.lua
        std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
 
        // Add default global mod search path
-       m_modspaths.push_front(m_path_game + DIR_DELIM "mods");
+       m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
        // Add world mod search path
        m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
        // Add addon mod search path
-       for(std::set<std::string>::const_iterator i = m_path_addons.begin();
-                       i != m_path_addons.end(); i++){
+       for(std::set<std::string>::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
-       infostream<<"- mod search paths:"<<std::endl;
        for(core::list<std::string>::Iterator i = m_modspaths.begin();
                        i != m_modspaths.end(); i++){
                std::string modspath = *i;
-               infostream<<"    "<<modspath<<std::endl;
+               infostream<<"- mods:   "<<modspath<<std::endl;
        }
        
+       // Create world if it doesn't exist
+       if(!initializeWorld(m_path_world, m_gamespec.id))
+               throw ServerError("Failed to initialize world");
+
        // Lock environment
        JMutexAutoLock envlock(m_env_mutex);
        JMutexAutoLock conlock(m_con_mutex);
 
        // Initialize scripting
        
-       infostream<<"Server: Initializing scripting"<<std::endl;
+       infostream<<"Server: Initializing Lua"<<std::endl;
        m_lua = script_init();
        assert(m_lua);
        // Export API
        scriptapi_export(m_lua, this);
        // Load and run builtin.lua
-       infostream<<"Server: Loading builtin Lua stuff from \""<<builtinpath
-                       <<"\""<<std::endl;
+       infostream<<"Server: Loading builtin.lua [\""
+                       <<builtinpath<<"\"]"<<std::endl;
        bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
        if(!success){
                errorstream<<"Server: Failed to load and run "
                                <<builtinpath<<std::endl;
                throw ModError("Failed to load and run "+builtinpath);
        }
-       // Load and run "mod" scripts
+       // Find mods in mod search paths
        m_mods = getMods(m_modspaths);
+       // Print 'em
+       infostream<<"Server: Loading mods: ";
+       for(core::list<ModSpec>::Iterator i = m_mods.begin();
+                       i != m_mods.end(); i++){
+               const ModSpec &mod = *i;
+               infostream<<mod.name<<" ";
+       }
+       infostream<<std::endl;
+       // Load and run "mod" scripts
        for(core::list<ModSpec>::Iterator i = m_mods.begin();
                        i != m_mods.end(); i++){
                const ModSpec &mod = *i;
-               infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
                std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
+               infostream<<"  ["<<padStringRight(mod.name, 12)<<"] [\""
+                               <<scriptpath<<"\"]"<<std::endl;
                bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
                if(!success){
                        errorstream<<"Server: Failed to load and run "
@@ -979,7 +998,7 @@ Server::Server(
 
 Server::~Server()
 {
-       infostream<<"Server::~Server()"<<std::endl;
+       infostream<<"Server destructing"<<std::endl;
 
        /*
                Send shutdown message
@@ -1069,6 +1088,8 @@ Server::~Server()
 void Server::start(unsigned short port)
 {
        DSTACK(__FUNCTION_NAME);
+       infostream<<"Starting server on port "<<port<<"..."<<std::endl;
+
        // Stop thread if already running
        m_thread.stop();
        
@@ -1080,7 +1101,17 @@ void Server::start(unsigned short port)
        m_thread.setRun(true);
        m_thread.Start();
        
-       infostream<<"Server started on port "<<port<<"."<<std::endl;
+       // ASCII art for the win!
+       actionstream
+       <<"        .__               __                   __   "<<std::endl
+       <<"  _____ |__| ____   _____/  |_  ____   _______/  |_ "<<std::endl
+       <<" /     \\|  |/    \\_/ __ \\   __\\/ __ \\ /  ___/\\   __\\"<<std::endl
+       <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl
+       <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl
+       <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl;
+       actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
+       actionstream<<"Server for gameid=\""<<m_gamespec.id
+                       <<"\" listening on port "<<port<<"."<<std::endl;
 }
 
 void Server::stop()
@@ -1108,6 +1139,11 @@ void Server::step(float dtime)
                JMutexAutoLock lock(m_step_dtime_mutex);
                m_step_dtime += dtime;
        }
+       // Throw if fatal error occurred in thread
+       std::string async_err = m_async_fatal_error.get();
+       if(async_err != ""){
+               throw ServerError(async_err);
+       }
 }
 
 void Server::AsyncRunStep()
@@ -1510,7 +1546,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: "
                                        <<removed_objects.size()<<" removed, "
                                        <<added_objects.size()<<" added, "
                                        <<"packet size is "<<reply.getSize()<<std::endl;
@@ -1673,15 +1709,13 @@ void Server::AsyncRunStep()
                if(m_unsent_map_edit_queue.size() >= 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.
@@ -1772,10 +1806,12 @@ void Server::AsyncRunStep()
                                break;*/
                }
 
-               if(got_any_events)
-               {
+               if(event_count >= 5){
                        infostream<<"Server: MapEditEvents:"<<std::endl;
                        prof.print(infostream);
+               } else if(event_count != 0){
+                       verbosestream<<"Server: MapEditEvents:"<<std::endl;
+                       prof.print(verbosestream);
                }
                
        }
@@ -1895,6 +1931,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                <<peer_id<<" not found"<<std::endl;
                return;
        }
+       
+       std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
 
        u8 peer_ser_ver = getClient(peer_id)->serialization_version;
 
@@ -1916,7 +1954,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 "
                                <<peer_id<<std::endl;
 
                // First byte after command is maximum supported
@@ -1934,6 +1972,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                
                if(deployed == SER_FMT_VER_INVALID)
                {
+                       actionstream<<"Server: A mismatched client tried to connect from "
+                                       <<addr_s<<std::endl;
                        infostream<<"Server: Cannot negotiate "
                                        "serialization version with peer "
                                        <<peer_id<<std::endl;
@@ -1959,6 +1999,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                if(net_proto_version == 0)
                {
+                       actionstream<<"Server: An old tried to connect from "<<addr_s
+                                       <<std::endl;
                        SendAccessDenied(m_con, peer_id, std::wstring(
                                        L"Your client's version is not supported.\n"
                                        L"Server version is ")
@@ -1971,6 +2013,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                {
                        if(net_proto_version != PROTOCOL_VERSION)
                        {
+                               actionstream<<"Server: A mismatched client tried to connect"
+                                               <<" from "<<addr_s<<std::endl;
                                SendAccessDenied(m_con, peer_id, std::wstring(
                                                L"Your client's version is not supported.\n"
                                                L"Server version is ")
@@ -1998,7 +2042,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                
                if(playername[0]=='\0')
                {
-                       infostream<<"Server: Player has empty name"<<std::endl;
+                       actionstream<<"Server: Player with an empty name "
+                                       <<"tried to connect from "<<addr_s<<std::endl;
                        SendAccessDenied(m_con, peer_id,
                                        L"Empty name");
                        return;
@@ -2006,12 +2051,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
                {
-                       infostream<<"Server: Player has invalid name"<<std::endl;
+                       actionstream<<"Server: Player with an invalid name "
+                                       <<"tried to connect from "<<addr_s<<std::endl;
                        SendAccessDenied(m_con, peer_id,
                                        L"Name contains unallowed characters");
                        return;
                }
 
+               infostream<<"Server: New connection: \""<<playername<<"\" from "
+                               <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
+
                // Get password
                char password[PASSWORD_SIZE];
                if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
@@ -2021,11 +2070,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                }
                else
                {
-                               for(u32 i=0; i<PASSWORD_SIZE-1; i++)
-                               {
-                                       password[i] = data[23+i];
-                               }
-                               password[PASSWORD_SIZE-1] = 0;
+                       for(u32 i=0; i<PASSWORD_SIZE-1; i++)
+                       {
+                               password[i] = data[23+i];
+                       }
+                       password[PASSWORD_SIZE-1] = 0;
                }
                
                // Add player to auth manager
@@ -2062,6 +2111,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        SendAccessDenied(m_con, peer_id, L"Invalid password");
                        return;
                }
+
+               // Do not allow multiple players in simple singleplayer mode.
+               // This isn't a perfect way to do it, but will suffice for now.
+               if(m_simple_singleplayer_mode && m_clients.size() > 1){
+                       infostream<<"Server: Not allowing another client to connect in"
+                                       <<" simple singleplayer mode"<<std::endl;
+                       SendAccessDenied(m_con, peer_id,
+                                       L"Running in simple singleplayer mode.");
+                       return;
+               }
                
                // Enforce user limit.
                // Don't enforce for users that have some admin right
@@ -2070,6 +2129,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
                                playername != g_settings->get("name"))
                {
+                       actionstream<<"Server: "<<playername<<" tried to join, but there"
+                                       <<" are already max_users="
+                                       <<g_settings->getU16("max_users")<<" players."<<std::endl;
                        SendAccessDenied(m_con, peer_id, L"Too many users.");
                        return;
                }
@@ -2080,7 +2142,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // If failed, cancel
                if(player == NULL)
                {
-                       infostream<<"Server: peer_id="<<peer_id
+                       errorstream<<"Server: peer_id="<<peer_id
                                        <<": failed to emerge player"<<std::endl;
                        return;
                }
@@ -2109,7 +2171,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 "
                                <<peer_id<<std::endl;
 
 
@@ -2120,6 +2182,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        Send some initialization data
                */
 
+               infostream<<"Server: Sending content to "
+                               <<getPlayerName(peer_id)<<std::endl;
+
                // Send item definitions
                SendItemDef(m_con, peer_id, m_itemdef);
                
@@ -2155,21 +2220,25 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        m_con.Send(peer_id, 0, data, true);
                }
                
-               // Send information about server to player in chat
-               SendChatMessage(peer_id, getStatusString());
-               
-               // Send information about joining in chat
+               // Note things in chat if not in simple singleplayer mode
+               if(!m_simple_singleplayer_mode)
                {
-                       std::wstring name = L"unknown";
-                       Player *player = m_env->getPlayer(peer_id);
-                       if(player != NULL)
-                               name = narrow_to_wide(player->getName());
+                       // Send information about server to player in chat
+                       SendChatMessage(peer_id, getStatusString());
                        
-                       std::wstring message;
-                       message += L"*** ";
-                       message += name;
-                       message += L" joined game";
-                       BroadcastChatMessage(message);
+                       // Send information about joining in chat
+                       {
+                               std::wstring name = L"unknown";
+                               Player *player = m_env->getPlayer(peer_id);
+                               if(player != NULL)
+                                       name = narrow_to_wide(player->getName());
+                               
+                               std::wstring message;
+                               message += L"*** ";
+                               message += name;
+                               message += L" joined game";
+                               BroadcastChatMessage(message);
+                       }
                }
                
                // Warnings about protocol version can be issued here
@@ -2374,7 +2443,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
        {
                // Strip command and create a stream
                std::string datastring((char*)&data[2], datasize-2);
-               infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
+               verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
                std::istringstream is(datastring, std::ios_base::binary);
                // Create an action
                InventoryAction *a = InventoryAction::deSerialize(is);
@@ -2785,19 +2854,20 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
        else if(command == TOSERVER_REQUEST_TEXTURES) {
                std::string datastring((char*)&data[2], datasize-2);
                std::istringstream is(datastring, std::ios_base::binary);
-
-               infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
-
+               
+               
                core::list<TextureRequest> tosend;
-
                u16 numtextures = readU16(is);
 
-               for(int i = 0; i < numtextures; i++) {
+               infostream<<"Sending "<<numtextures<<" textures to "
+                               <<getPlayerName(peer_id)<<std::endl;
+               verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
 
+               for(int i = 0; i < numtextures; i++) {
                        std::string name = deSerializeString(is);
-
                        tosend.push_back(TextureRequest(name));
-                       infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl;
+                       verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
+                                       <<name<<std::endl;
                }
 
                SendTexturesRequested(peer_id, tosend);
@@ -2830,11 +2900,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                PointedThing pointed;
                pointed.deSerialize(tmp_is);
 
-               infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
+               verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
+                               <<item_i<<", pointed="<<pointed.dump()<<std::endl;
 
                if(player->hp == 0)
                {
-                       infostream<<"TOSERVER_INTERACT: "<<srp->getName()
+                       verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
                                <<" tried to interact, but is dead!"<<std::endl;
                        return;
                }
@@ -2859,7 +2930,7 @@ 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"<<std::endl;
                                return;
                        }
@@ -2947,7 +3018,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        return;
 
                                actionstream<<player->getName()<<" punches object "
-                                       <<pointed.object_id<<std::endl;
+                                               <<pointed.object_id<<": "
+                                               <<pointed_object->getDescription()<<std::endl;
 
                                ItemStack punchitem = srp->getWieldedItem();
                                ToolCapabilities toolcap =
@@ -3016,7 +3088,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        return;
 
                                actionstream<<player->getName()<<" right-clicks object "
-                                       <<pointed.object_id<<std::endl;
+                                               <<pointed.object_id<<": "
+                                               <<pointed_object->getDescription()<<std::endl;
 
                                // Do stuff
                                pointed_object->rightClick(srp);
@@ -3223,7 +3296,7 @@ core::list<PlayerInfo> Server::getPlayerInfo()
 void Server::peerAdded(con::Peer *peer)
 {
        DSTACK(__FUNCTION_NAME);
-       infostream<<"Server::peerAdded(): peer->id="
+       verbosestream<<"Server::peerAdded(): peer->id="
                        <<peer->id<<std::endl;
        
        PeerChange c;
@@ -3236,7 +3309,7 @@ void Server::peerAdded(con::Peer *peer)
 void Server::deletingPeer(con::Peer *peer, bool timeout)
 {
        DSTACK(__FUNCTION_NAME);
-       infostream<<"Server::deletingPeer(): peer->id="
+       verbosestream<<"Server::deletingPeer(): peer->id="
                        <<peer->id<<", timeout="<<timeout<<std::endl;
        
        PeerChange c;
@@ -3318,8 +3391,8 @@ void Server::SendItemDef(con::Connection &con, u16 peer_id,
 
        // Make data buffer
        std::string s = os.str();
-       infostream<<"Server::SendItemDef(): Sending item definitions: size="
-                       <<s.size()<<std::endl;
+       verbosestream<<"Server: Sending item definitions to id("<<peer_id
+                       <<"): size="<<s.size()<<std::endl;
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
        // Send as reliable
        con.Send(peer_id, 0, data, true);
@@ -3345,8 +3418,8 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
 
        // Make data buffer
        std::string s = os.str();
-       infostream<<"Server::SendNodeDef(): Sending node definitions: size="
-                       <<s.size()<<std::endl;
+       verbosestream<<"Server: Sending node definitions to id("<<peer_id
+                       <<"): size="<<s.size()<<std::endl;
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
        // Send as reliable
        con.Send(peer_id, 0, data, true);
@@ -3497,7 +3570,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=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
                                <<" pitch="<<pitch
                                <<" yaw="<<yaw
@@ -3745,71 +3818,72 @@ void Server::SendBlocks(float dtime)
        }
 }
 
-void Server::PrepareTextures() {
+void Server::PrepareTextures()
+{
        DSTACK(__FUNCTION_NAME);
 
-       infostream<<"Server::PrepareTextures(): Calculate sha1 sums of textures"<<std::endl;
+       infostream<<"Server: Calculating texture checksums"<<std::endl;
 
        for(core::list<ModSpec>::Iterator i = m_mods.begin();
-                                       i != m_mods.end(); i++){
-                       const ModSpec &mod = *i;
-                       std::string texturepath = mod.path + DIR_DELIM + "textures";
-                       std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
-                       for(u32 j=0; j<dirlist.size(); j++){
-                               if(dirlist[j].dir) // Ignode dirs
-                                       continue;
-                               std::string tname = dirlist[j].name;
-                               // if name contains illegal characters, ignore the texture
-                               if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
-                                       errorstream<<"Server: ignoring illegal texture name: \""
-                                                       <<tname<<"\""<<std::endl;
-                                       continue;
-                               }
-                               std::string tpath = texturepath + DIR_DELIM + tname;
-                               // Read data
-                               std::ifstream fis(tpath.c_str(), std::ios_base::binary);
-                               if(fis.good() == false){
-                                       errorstream<<"Server::PrepareTextures(): Could not open \""
-                                                       <<tname<<"\" for reading"<<std::endl;
-                                       continue;
-                               }
-                               std::ostringstream tmp_os(std::ios_base::binary);
-                               bool bad = false;
-                               for(;;){
-                                       char buf[1024];
-                                       fis.read(buf, 1024);
-                                       std::streamsize len = fis.gcount();
-                                       tmp_os.write(buf, len);
-                                       if(fis.eof())
-                                               break;
-                                       if(!fis.good()){
-                                               bad = true;
-                                               break;
-                                       }
-                               }
-                               if(bad){
-                                       errorstream<<"Server::PrepareTextures(): Failed to read \""
-                                                       <<tname<<"\""<<std::endl;
-                                       continue;
-                               }
-                               if(tmp_os.str().length() == 0){
-                                       errorstream<<"Server::PrepareTextures(): Empty file \""
-                                                       <<tpath<<"\""<<std::endl;
-                                       continue;
+                       i != m_mods.end(); i++){
+               const ModSpec &mod = *i;
+               std::string texturepath = mod.path + DIR_DELIM + "textures";
+               std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
+               for(u32 j=0; j<dirlist.size(); j++){
+                       if(dirlist[j].dir) // Ignode dirs
+                               continue;
+                       std::string tname = dirlist[j].name;
+                       // if name contains illegal characters, ignore the texture
+                       if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
+                               errorstream<<"Server: ignoring illegal texture name: \""
+                                               <<tname<<"\""<<std::endl;
+                               continue;
+                       }
+                       std::string tpath = texturepath + DIR_DELIM + tname;
+                       // Read data
+                       std::ifstream fis(tpath.c_str(), std::ios_base::binary);
+                       if(fis.good() == false){
+                               errorstream<<"Server::PrepareTextures(): Could not open \""
+                                               <<tname<<"\" for reading"<<std::endl;
+                               continue;
+                       }
+                       std::ostringstream tmp_os(std::ios_base::binary);
+                       bool bad = false;
+                       for(;;){
+                               char buf[1024];
+                               fis.read(buf, 1024);
+                               std::streamsize len = fis.gcount();
+                               tmp_os.write(buf, len);
+                               if(fis.eof())
+                                       break;
+                               if(!fis.good()){
+                                       bad = true;
+                                       break;
                                }
+                       }
+                       if(bad){
+                               errorstream<<"Server::PrepareTextures(): Failed to read \""
+                                               <<tname<<"\""<<std::endl;
+                               continue;
+                       }
+                       if(tmp_os.str().length() == 0){
+                               errorstream<<"Server::PrepareTextures(): Empty file \""
+                                               <<tpath<<"\""<<std::endl;
+                               continue;
+                       }
 
-                               SHA1 sha1;
-                               sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
+                       SHA1 sha1;
+                       sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
 
-                               unsigned char *digest = sha1.getDigest();
-                               std::string digest_string = base64_encode(digest, 20);
+                       unsigned char *digest = sha1.getDigest();
+                       std::string digest_string = base64_encode(digest, 20);
 
-                               free(digest);
+                       free(digest);
 
-                               // Put in list
-                               this->m_Textures[tname] = TextureInformation(tpath,digest_string);
-                               infostream<<"Server::PrepareTextures(): added sha1 for "<< tname <<std::endl;
-                       }
+                       // Put in list
+                       this->m_Textures[tname] = TextureInformation(tpath,digest_string);
+                       verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
+               }
        }
 }
 
@@ -3829,7 +3903,8 @@ struct SendableTextureAnnouncement
 void Server::SendTextureAnnouncement(u16 peer_id){
        DSTACK(__FUNCTION_NAME);
 
-       infostream<<"Server::SendTextureAnnouncement()"<<std::endl;
+       verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
+                       <<std::endl;
 
        core::list<SendableTextureAnnouncement> texture_announcements;
 
@@ -3866,7 +3941,6 @@ void Server::SendTextureAnnouncement(u16 peer_id){
 
        // Make data buffer
        std::string s = os.str();
-       infostream<<"Server::SendTextureAnnouncement(): Send to client"<<std::endl;
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
 
        // Send as reliable
@@ -3891,7 +3965,8 @@ struct SendableTexture
 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
        DSTACK(__FUNCTION_NAME);
 
-       infostream<<"Server::SendTexturesRequested(): Sending textures to client"<<std::endl;
+       verbosestream<<"Server::SendTexturesRequested(): "
+                       <<"Sending textures to client"<<std::endl;
 
        /* Read textures */
 
@@ -3987,7 +4062,8 @@ void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend
 
                        // Make data buffer
                        std::string s = os.str();
-                       infostream<<"Server::SendTexturesRequested(): bunch "<<i<<"/"<<num_bunches
+                       verbosestream<<"Server::SendTexturesRequested(): bunch "
+                                       <<i<<"/"<<num_bunches
                                        <<" textures="<<texture_bunches[i].size()
                                        <<" size=" <<s.size()<<std::endl;
                        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
@@ -4106,6 +4182,40 @@ std::wstring Server::getStatusString()
        return os.str();
 }
 
+u64 Server::getPlayerAuthPrivs(const std::string &name)
+{
+       try{
+               return m_authmanager.getPrivs(name);
+       }
+       catch(AuthNotFoundException &e)
+       {
+               dstream<<"WARNING: Auth not found for "<<name<<std::endl;
+               return 0;
+       }
+}
+
+void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
+{
+       try{
+               return m_authmanager.setPrivs(name, privs);
+       }
+       catch(AuthNotFoundException &e)
+       {
+               dstream<<"WARNING: Auth not found for "<<name<<std::endl;
+       }
+}
+
+u64 Server::getPlayerEffectivePrivs(const std::string &name)
+{
+       // Local player gets all privileges regardless of
+       // what's set on their account.
+       if(m_simple_singleplayer_mode)
+               return PRIV_ALL;
+       if(name == g_settings->get("name"))
+               return PRIV_ALL;
+       return getPlayerAuthPrivs(name);
+}
+
 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
 {
        // Add player to auth manager
@@ -4481,7 +4591,7 @@ void Server::handlePeerChanges()
        {
                PeerChange c = m_peer_change_queue.pop_front();
 
-               infostream<<"Server: Handling peer change: "
+               verbosestream<<"Server: Handling peer change: "
                                <<"id="<<c.peer_id<<", timeout="<<c.timeout
                                <<std::endl;
 
@@ -4494,27 +4604,14 @@ 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);
-       }
+       return getPlayerEffectivePrivs(playername);
 }
 
 void dedicated_server_loop(Server &server, bool &kill)
 {
        DSTACK(__FUNCTION_NAME);
        
-       infostream<<DTIME<<std::endl;
-       infostream<<"========================"<<std::endl;
-       infostream<<"Running dedicated server"<<std::endl;
-       infostream<<"========================"<<std::endl;
-       infostream<<std::endl;
+       verbosestream<<"dedicated_server_loop()"<<std::endl;
 
        IntervalLimiter m_profiler_interval;
 
@@ -4531,7 +4628,7 @@ void dedicated_server_loop(Server &server, bool &kill)
 
                if(server.getShutdownRequested() || kill)
                {
-                       infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
+                       infostream<<"Dedicated server quitting"<<std::endl;
                        break;
                }
 
@@ -4549,30 +4646,6 @@ void dedicated_server_loop(Server &server, bool &kill)
                                g_profiler->clear();
                        }
                }
-               
-               /*
-                       Player info
-               */
-               static int counter = 0;
-               counter--;
-               if(counter <= 0)
-               {
-                       counter = 10;
-
-                       core::list<PlayerInfo> list = server.getPlayerInfo();
-                       core::list<PlayerInfo>::Iterator i;
-                       static u32 sum_old = 0;
-                       u32 sum = PIChecksum(list);
-                       if(sum != sum_old)
-                       {
-                               infostream<<DTIME<<"Player info:"<<std::endl;
-                               for(i=list.begin(); i!=list.end(); i++)
-                               {
-                                       i->PrintLine(&infostream);
-                               }
-                       }
-                       sum_old = sum;
-               }
        }
 }