]> git.lizzy.rs Git - minetest.git/blobdiff - src/server.cpp
Clientiface: remove "value is dummy" from docs
[minetest.git] / src / server.cpp
index e9aee47b2dd1b8dbe1a271f79bce0edaecba18d7..572533146555d9d923b17aed3e52297634978773 100644 (file)
@@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "ban.h"
 #include "environment.h"
 #include "map.h"
 #include "ban.h"
 #include "environment.h"
 #include "map.h"
-#include "jthread/jmutexautolock.h"
+#include "threading/mutex_auto_lock.h"
 #include "constants.h"
 #include "voxel.h"
 #include "config.h"
 #include "constants.h"
 #include "voxel.h"
 #include "config.h"
@@ -71,65 +71,48 @@ class ClientNotFoundException : public BaseException
        {}
 };
 
        {}
 };
 
-class ServerThread : public JThread
+class ServerThread : public Thread
 {
 {
-       Server *m_server;
-
 public:
 
        ServerThread(Server *server):
 public:
 
        ServerThread(Server *server):
-               JThread(),
+               Thread("Server"),
                m_server(server)
                m_server(server)
-       {
-       }
+       {}
+
+       void *run();
 
 
-       void * Thread();
+private:
+       Server *m_server;
 };
 
 };
 
-void * ServerThread::Thread()
+void *ServerThread::run()
 {
 {
-       log_register_thread("ServerThread");
-
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        BEGIN_DEBUG_EXCEPTION_HANDLER
 
        m_server->AsyncRunStep(true);
 
        BEGIN_DEBUG_EXCEPTION_HANDLER
 
        m_server->AsyncRunStep(true);
 
-       ThreadStarted();
-
-       porting::setThreadName("ServerThread");
-
-       while(!StopRequested())
-       {
-               try{
+       while (!stopRequested()) {
+               try {
                        //TimeTaker timer("AsyncRunStep() + Receive()");
 
                        m_server->AsyncRunStep();
 
                        m_server->Receive();
 
                        //TimeTaker timer("AsyncRunStep() + Receive()");
 
                        m_server->AsyncRunStep();
 
                        m_server->Receive();
 
-               }
-               catch(con::NoIncomingDataException &e)
-               {
-               }
-               catch(con::PeerNotFoundException &e)
-               {
+               } catch (con::NoIncomingDataException &e) {
+               } catch (con::PeerNotFoundException &e) {
                        infostream<<"Server: PeerNotFoundException"<<std::endl;
                        infostream<<"Server: PeerNotFoundException"<<std::endl;
-               }
-               catch(ClientNotFoundException &e)
-               {
-               }
-               catch(con::ConnectionBindFailed &e)
-               {
-                       m_server->setAsyncFatalError(e.what());
-               }
-               catch(LuaError &e)
-               {
+               } catch (ClientNotFoundException &e) {
+               } catch (con::ConnectionBindFailed &e) {
                        m_server->setAsyncFatalError(e.what());
                        m_server->setAsyncFatalError(e.what());
+               } catch (LuaError &e) {
+                       m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
                }
        }
 
                }
        }
 
-       END_DEBUG_EXCEPTION_HANDLER(errorstream)
+       END_DEBUG_EXCEPTION_HANDLER
 
        return NULL;
 }
 
        return NULL;
 }
@@ -165,7 +148,8 @@ Server::Server(
                const std::string &path_world,
                const SubgameSpec &gamespec,
                bool simple_singleplayer_mode,
                const std::string &path_world,
                const SubgameSpec &gamespec,
                bool simple_singleplayer_mode,
-               bool ipv6
+               bool ipv6,
+               ChatInterface *iface
        ):
        m_path_world(path_world),
        m_gamespec(gamespec),
        ):
        m_path_world(path_world),
        m_gamespec(gamespec),
@@ -191,6 +175,8 @@ Server::Server(
        m_uptime(0),
        m_clients(&m_con),
        m_shutdown_requested(false),
        m_uptime(0),
        m_clients(&m_con),
        m_shutdown_requested(false),
+       m_shutdown_ask_reconnect(false),
+       m_admin_chat(iface),
        m_ignore_map_edit_events(false),
        m_ignore_map_edit_events_peer_id(0),
        m_next_sound_id(0)
        m_ignore_map_edit_events(false),
        m_ignore_map_edit_events_peer_id(0),
        m_next_sound_id(0)
@@ -277,8 +263,8 @@ Server::Server(
                errorstream << std::endl;
        }
 
                errorstream << std::endl;
        }
 
-       // Lock environment
-       JMutexAutoLock envlock(m_env_mutex);
+       //lock environment
+       MutexAutoLock envlock(m_env_mutex);
 
        // Load mapgen params from Settings
        m_emerge->loadMapgenParams();
 
        // Load mapgen params from Settings
        m_emerge->loadMapgenParams();
@@ -292,41 +278,30 @@ Server::Server(
        m_script = new GameScripting(this);
 
        std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
        m_script = new GameScripting(this);
 
        std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
-       std::string error_msg;
 
 
-       if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
-               throw ModError("Failed to load and run " + script_path
-                               + "\nError from Lua:\n" + error_msg);
+       m_script->loadMod(script_path, BUILTIN_MOD_NAME);
 
        // Print mods
        infostream << "Server: Loading mods: ";
        for(std::vector<ModSpec>::iterator i = m_mods.begin();
 
        // Print mods
        infostream << "Server: Loading mods: ";
        for(std::vector<ModSpec>::iterator i = m_mods.begin();
-                       i != m_mods.end(); i++) {
+                       i != m_mods.end(); ++i) {
                const ModSpec &mod = *i;
                infostream << mod.name << " ";
        }
        infostream << std::endl;
        // Load and run "mod" scripts
                const ModSpec &mod = *i;
                infostream << mod.name << " ";
        }
        infostream << std::endl;
        // Load and run "mod" scripts
-       for (std::vector<ModSpec>::iterator i = m_mods.begin();
-                       i != m_mods.end(); i++) {
-               const ModSpec &mod = *i;
+       for (std::vector<ModSpec>::iterator it = m_mods.begin();
+                       it != m_mods.end(); ++it) {
+               const ModSpec &mod = *it;
                if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
                if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
-                       std::ostringstream err;
-                       err << "Error loading mod \"" << mod.name
-                                       << "\": mod_name does not follow naming conventions: "
-                                       << "Only chararacters [a-z0-9_] are allowed." << std::endl;
-                       errorstream << err.str().c_str();
-                       throw ModError(err.str());
+                       throw ModError("Error loading mod \"" + mod.name +
+                               "\": Mod name does not follow naming conventions: "
+                               "Only chararacters [a-z0-9_] are allowed.");
                }
                }
-               std::string script_path = mod.path + DIR_DELIM "init.lua";
+               std::string script_path = mod.path + DIR_DELIM "init.lua";
                infostream << "  [" << padStringRight(mod.name, 12) << "] [\""
                                << script_path << "\"]" << std::endl;
                infostream << "  [" << padStringRight(mod.name, 12) << "] [\""
                                << script_path << "\"]" << std::endl;
-               if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
-                       errorstream << "Server: Failed to load and run "
-                                       << script_path << std::endl;
-                       throw ModError("Failed to load and run " + script_path
-                                       + "\nError from Lua:\n" + error_msg);
-               }
+               m_script->loadMod(script_path, mod.name);
        }
 
        // Read Textures and calculate sha1 sums
        }
 
        // Read Textures and calculate sha1 sums
@@ -389,15 +364,28 @@ Server::~Server()
        SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
 
        {
        SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
 
        {
-               JMutexAutoLock envlock(m_env_mutex);
+               MutexAutoLock envlock(m_env_mutex);
 
                // Execute script shutdown hooks
                m_script->on_shutdown();
 
 
                // Execute script shutdown hooks
                m_script->on_shutdown();
 
-               infostream<<"Server: Saving players"<<std::endl;
+               infostream << "Server: Saving players" << std::endl;
                m_env->saveLoadedPlayers();
 
                m_env->saveLoadedPlayers();
 
-               infostream<<"Server: Saving environment metadata"<<std::endl;
+               infostream << "Server: Kicking players" << std::endl;
+               std::string kick_msg;
+               bool reconnect = false;
+               if (getShutdownRequested()) {
+                       reconnect = m_shutdown_ask_reconnect;
+                       kick_msg = m_shutdown_msg;
+               }
+               if (kick_msg == "") {
+                       kick_msg = g_settings->get("kick_msg_shutdown");
+               }
+               m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
+                       kick_msg, reconnect);
+
+               infostream << "Server: Saving environment metadata" << std::endl;
                m_env->saveMeta();
        }
 
                m_env->saveMeta();
        }
 
@@ -429,14 +417,14 @@ Server::~Server()
        // Delete detached inventories
        for (std::map<std::string, Inventory*>::iterator
                        i = m_detached_inventories.begin();
        // Delete detached inventories
        for (std::map<std::string, Inventory*>::iterator
                        i = m_detached_inventories.begin();
-                       i != m_detached_inventories.end(); i++) {
+                       i != m_detached_inventories.end(); ++i) {
                delete i->second;
        }
 }
 
 void Server::start(Address bind_addr)
 {
                delete i->second;
        }
 }
 
 void Server::start(Address bind_addr)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        m_bind_addr = bind_addr;
 
 
        m_bind_addr = bind_addr;
 
@@ -444,14 +432,14 @@ void Server::start(Address bind_addr)
                        << bind_addr.serializeString() <<"..."<<std::endl;
 
        // Stop thread if already running
                        << bind_addr.serializeString() <<"..."<<std::endl;
 
        // Stop thread if already running
-       m_thread->Stop();
+       m_thread->stop();
 
        // Initialize connection
        m_con.SetTimeoutMs(30);
        m_con.Serve(bind_addr);
 
        // Start thread
 
        // Initialize connection
        m_con.SetTimeoutMs(30);
        m_con.Serve(bind_addr);
 
        // Start thread
-       m_thread->Start();
+       m_thread->start();
 
        // ASCII art for the win!
        actionstream
 
        // ASCII art for the win!
        actionstream
@@ -469,14 +457,14 @@ void Server::start(Address bind_addr)
 
 void Server::stop()
 {
 
 void Server::stop()
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        infostream<<"Server: Stopping and waiting threads"<<std::endl;
 
        // Stop threads (set run=false first so both start stopping)
 
        infostream<<"Server: Stopping and waiting threads"<<std::endl;
 
        // Stop threads (set run=false first so both start stopping)
-       m_thread->Stop();
+       m_thread->stop();
        //m_emergethread.setRun(false);
        //m_emergethread.setRun(false);
-       m_thread->Wait();
+       m_thread->wait();
        //m_emergethread.stop();
 
        infostream<<"Server: Threads stopped"<<std::endl;
        //m_emergethread.stop();
 
        infostream<<"Server: Threads stopped"<<std::endl;
@@ -484,38 +472,35 @@ void Server::stop()
 
 void Server::step(float dtime)
 {
 
 void Server::step(float dtime)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        // Limit a bit
        // Limit a bit
-       if(dtime > 2.0)
+       if (dtime > 2.0)
                dtime = 2.0;
        {
                dtime = 2.0;
        {
-               JMutexAutoLock lock(m_step_dtime_mutex);
+               MutexAutoLock 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();
                m_step_dtime += dtime;
        }
        // Throw if fatal error occurred in thread
        std::string async_err = m_async_fatal_error.get();
-       if(async_err != "") {
-               if (m_simple_singleplayer_mode) {
-                       throw ServerError(async_err);
-               }
-               else {
-                       errorstream << "UNRECOVERABLE error occurred. Stopping server. "
-                                       << "Please fix the following error:" << std::endl
-                                       << async_err << std::endl;
-                       FATAL_ERROR(async_err.c_str());
+       if (!async_err.empty()) {
+               if (!m_simple_singleplayer_mode) {
+                       m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
+                               g_settings->get("kick_msg_crash"),
+                               g_settings->getBool("ask_reconnect_on_crash"));
                }
                }
+               throw ServerError(async_err);
        }
 }
 
 void Server::AsyncRunStep(bool initial_step)
 {
        }
 }
 
 void Server::AsyncRunStep(bool initial_step)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        g_profiler->add("Server::AsyncRunStep (num)", 1);
 
        float dtime;
        {
 
        g_profiler->add("Server::AsyncRunStep (num)", 1);
 
        float dtime;
        {
-               JMutexAutoLock lock1(m_step_dtime_mutex);
+               MutexAutoLock lock1(m_step_dtime_mutex);
                dtime = m_step_dtime;
        }
 
                dtime = m_step_dtime;
        }
 
@@ -533,7 +518,7 @@ void Server::AsyncRunStep(bool initial_step)
        //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
 
        {
        //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
 
        {
-               JMutexAutoLock lock1(m_step_dtime_mutex);
+               MutexAutoLock lock1(m_step_dtime_mutex);
                m_step_dtime -= dtime;
        }
 
                m_step_dtime -= dtime;
        }
 
@@ -564,7 +549,7 @@ void Server::AsyncRunStep(bool initial_step)
        }
 
        {
        }
 
        {
-               JMutexAutoLock lock(m_env_mutex);
+               MutexAutoLock lock(m_env_mutex);
                // Figure out and report maximum lag to environment
                float max_lag = m_env->getMaxLagEstimate();
                max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
                // Figure out and report maximum lag to environment
                float max_lag = m_env->getMaxLagEstimate();
                max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
@@ -584,11 +569,28 @@ void Server::AsyncRunStep(bool initial_step)
        static const float map_timer_and_unload_dtime = 2.92;
        if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
        {
        static const float map_timer_and_unload_dtime = 2.92;
        if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
        {
-               JMutexAutoLock lock(m_env_mutex);
+               MutexAutoLock lock(m_env_mutex);
                // Run Map's timers and unload unused data
                ScopeProfiler sp(g_profiler, "Server: map timer and unload");
                m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
                // Run Map's timers and unload unused data
                ScopeProfiler sp(g_profiler, "Server: map timer and unload");
                m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
-                               g_settings->getFloat("server_unload_unused_data_timeout"));
+                       g_settings->getFloat("server_unload_unused_data_timeout"),
+                       U32_MAX);
+       }
+
+       /*
+               Listen to the admin chat, if available
+       */
+       if (m_admin_chat) {
+               if (!m_admin_chat->command_queue.empty()) {
+                       MutexAutoLock lock(m_env_mutex);
+                       while (!m_admin_chat->command_queue.empty()) {
+                               ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
+                               handleChatInterfaceEvent(evt);
+                               delete evt;
+                       }
+               }
+               m_admin_chat->outgoing_queue.push_back(
+                       new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
        }
 
        /*
        }
 
        /*
@@ -601,7 +603,7 @@ void Server::AsyncRunStep(bool initial_step)
        {
                m_liquid_transform_timer -= m_liquid_transform_every;
 
        {
                m_liquid_transform_timer -= m_liquid_transform_every;
 
-               JMutexAutoLock lock(m_env_mutex);
+               MutexAutoLock lock(m_env_mutex);
 
                ScopeProfiler sp(g_profiler, "Server: liquid transform");
 
 
                ScopeProfiler sp(g_profiler, "Server: liquid transform");
 
@@ -662,9 +664,9 @@ void Server::AsyncRunStep(bool initial_step)
        */
        {
                //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
        */
        {
                //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
-               JMutexAutoLock envlock(m_env_mutex);
+               MutexAutoLock envlock(m_env_mutex);
 
 
-               m_clients.Lock();
+               m_clients.lock();
                std::map<u16, RemoteClient*> clients = m_clients.getClientList();
                ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
 
                std::map<u16, RemoteClient*> clients = m_clients.getClientList();
                ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
 
@@ -679,10 +681,9 @@ void Server::AsyncRunStep(bool initial_step)
                radius *= MAP_BLOCKSIZE;
                player_radius *= MAP_BLOCKSIZE;
 
                radius *= MAP_BLOCKSIZE;
                player_radius *= MAP_BLOCKSIZE;
 
-               for(std::map<u16, RemoteClient*>::iterator
+               for (std::map<u16, RemoteClient*>::iterator
                        i = clients.begin();
                        i = clients.begin();
-                       i != clients.end(); ++i)
-               {
+                       i != clients.end(); ++i) {
                        RemoteClient *client = i->second;
 
                        // If definitions and textures have not been sent, don't
                        RemoteClient *client = i->second;
 
                        // If definitions and textures have not been sent, don't
@@ -691,27 +692,23 @@ void Server::AsyncRunStep(bool initial_step)
                                continue;
 
                        Player *player = m_env->getPlayer(client->peer_id);
                                continue;
 
                        Player *player = m_env->getPlayer(client->peer_id);
-                       if(player==NULL)
-                       {
+                       if(player == NULL) {
                                // This can happen if the client timeouts somehow
                                // This can happen if the client timeouts somehow
-                               /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
+                               /*warningstream<<FUNCTION_NAME<<": Client "
                                                <<client->peer_id
                                                <<" has no associated player"<<std::endl;*/
                                continue;
                        }
                                                <<client->peer_id
                                                <<" has no associated player"<<std::endl;*/
                                continue;
                        }
-                       v3s16 pos = floatToInt(player->getPosition(), BS);
 
 
-                       std::set<u16> removed_objects;
-                       std::set<u16> added_objects;
-                       m_env->getRemovedActiveObjects(pos, radius, player_radius,
+                       std::queue<u16> removed_objects;
+                       std::queue<u16> added_objects;
+                       m_env->getRemovedActiveObjects(player, radius, player_radius,
                                        client->m_known_objects, removed_objects);
                                        client->m_known_objects, removed_objects);
-                       m_env->getAddedActiveObjects(pos, radius, player_radius,
+                       m_env->getAddedActiveObjects(player, radius, player_radius,
                                        client->m_known_objects, added_objects);
 
                        // Ignore if nothing happened
                                        client->m_known_objects, added_objects);
 
                        // Ignore if nothing happened
-                       if(removed_objects.empty() && added_objects.empty())
-                       {
-                               //infostream<<"active objects: none changed"<<std::endl;
+                       if (removed_objects.empty() && added_objects.empty()) {
                                continue;
                        }
 
                                continue;
                        }
 
@@ -722,12 +719,9 @@ void Server::AsyncRunStep(bool initial_step)
                        // Handle removed objects
                        writeU16((u8*)buf, removed_objects.size());
                        data_buffer.append(buf, 2);
                        // Handle removed objects
                        writeU16((u8*)buf, removed_objects.size());
                        data_buffer.append(buf, 2);
-                       for(std::set<u16>::iterator
-                                       i = removed_objects.begin();
-                                       i != removed_objects.end(); ++i)
-                       {
+                       while (!removed_objects.empty()) {
                                // Get object
                                // Get object
-                               u16 id = *i;
+                               u16 id = removed_objects.front();
                                ServerActiveObject* obj = m_env->getActiveObject(id);
 
                                // Add to data buffer for sending
                                ServerActiveObject* obj = m_env->getActiveObject(id);
 
                                // Add to data buffer for sending
@@ -739,23 +733,21 @@ void Server::AsyncRunStep(bool initial_step)
 
                                if(obj && obj->m_known_by_count > 0)
                                        obj->m_known_by_count--;
 
                                if(obj && obj->m_known_by_count > 0)
                                        obj->m_known_by_count--;
+                               removed_objects.pop();
                        }
 
                        // Handle added objects
                        writeU16((u8*)buf, added_objects.size());
                        data_buffer.append(buf, 2);
                        }
 
                        // Handle added objects
                        writeU16((u8*)buf, added_objects.size());
                        data_buffer.append(buf, 2);
-                       for(std::set<u16>::iterator
-                                       i = added_objects.begin();
-                                       i != added_objects.end(); ++i)
-                       {
+                       while (!added_objects.empty()) {
                                // Get object
                                // Get object
-                               u16 id = *i;
+                               u16 id = added_objects.front();
                                ServerActiveObject* obj = m_env->getActiveObject(id);
 
                                // Get object type
                                u8 type = ACTIVEOBJECT_TYPE_INVALID;
                                if(obj == NULL)
                                ServerActiveObject* obj = m_env->getActiveObject(id);
 
                                // Get object type
                                u8 type = ACTIVEOBJECT_TYPE_INVALID;
                                if(obj == NULL)
-                                       infostream<<"WARNING: "<<__FUNCTION_NAME
+                                       warningstream<<FUNCTION_NAME
                                                        <<": NULL object"<<std::endl;
                                else
                                        type = obj->getSendType();
                                                        <<": NULL object"<<std::endl;
                                else
                                        type = obj->getSendType();
@@ -777,6 +769,8 @@ void Server::AsyncRunStep(bool initial_step)
 
                                if(obj)
                                        obj->m_known_by_count++;
 
                                if(obj)
                                        obj->m_known_by_count++;
+
+                               added_objects.pop();
                        }
 
                        u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
                        }
 
                        u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
@@ -785,14 +779,14 @@ void Server::AsyncRunStep(bool initial_step)
                                        << added_objects.size() << " added, "
                                        << "packet size is " << pktSize << std::endl;
                }
                                        << added_objects.size() << " added, "
                                        << "packet size is " << pktSize << std::endl;
                }
-               m_clients.Unlock();
+               m_clients.unlock();
        }
 
        /*
                Send object messages
        */
        {
        }
 
        /*
                Send object messages
        */
        {
-               JMutexAutoLock envlock(m_env_mutex);
+               MutexAutoLock envlock(m_env_mutex);
                ScopeProfiler sp(g_profiler, "Server: sending object messages");
 
                // Key = object id
                ScopeProfiler sp(g_profiler, "Server: sending object messages");
 
                // Key = object id
@@ -818,7 +812,7 @@ void Server::AsyncRunStep(bool initial_step)
                        message_list->push_back(aom);
                }
 
                        message_list->push_back(aom);
                }
 
-               m_clients.Lock();
+               m_clients.lock();
                std::map<u16, RemoteClient*> clients = m_clients.getClientList();
                // Route data to every client
                for (std::map<u16, RemoteClient*>::iterator
                std::map<u16, RemoteClient*> clients = m_clients.getClientList();
                // Route data to every client
                for (std::map<u16, RemoteClient*>::iterator
@@ -869,7 +863,7 @@ void Server::AsyncRunStep(bool initial_step)
                                SendActiveObjectMessages(client->peer_id, unreliable_data, false);
                        }
                }
                                SendActiveObjectMessages(client->peer_id, unreliable_data, false);
                        }
                }
-               m_clients.Unlock();
+               m_clients.unlock();
 
                // Clear buffered_messages
                for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
 
                // Clear buffered_messages
                for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
@@ -884,7 +878,7 @@ void Server::AsyncRunStep(bool initial_step)
        */
        {
                // We will be accessing the environment
        */
        {
                // We will be accessing the environment
-               JMutexAutoLock lock(m_env_mutex);
+               MutexAutoLock lock(m_env_mutex);
 
                // Don't send too many at a time
                //u32 count = 0;
 
                // Don't send too many at a time
                //u32 count = 0;
@@ -938,7 +932,7 @@ void Server::AsyncRunStep(bool initial_step)
                                break;
                        default:
                                prof.add("unknown", 1);
                                break;
                        default:
                                prof.add("unknown", 1);
-                               infostream << "WARNING: Server: Unknown MapEditEvent "
+                               warningstream << "Server: Unknown MapEditEvent "
                                                << ((u32)event->type) << std::endl;
                                break;
                        }
                                                << ((u32)event->type) << std::endl;
                                break;
                        }
@@ -1005,7 +999,7 @@ void Server::AsyncRunStep(bool initial_step)
                if(counter >= g_settings->getFloat("server_map_save_interval"))
                {
                        counter = 0.0;
                if(counter >= g_settings->getFloat("server_map_save_interval"))
                {
                        counter = 0.0;
-                       JMutexAutoLock lock(m_env_mutex);
+                       MutexAutoLock lock(m_env_mutex);
 
                        ScopeProfiler sp(g_profiler, "Server: saving stuff");
 
 
                        ScopeProfiler sp(g_profiler, "Server: saving stuff");
 
@@ -1028,7 +1022,7 @@ void Server::AsyncRunStep(bool initial_step)
 
 void Server::Receive()
 {
 
 void Server::Receive()
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        SharedBuffer<u8> data;
        u16 peer_id;
        try {
        SharedBuffer<u8> data;
        u16 peer_id;
        try {
@@ -1061,18 +1055,18 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
 {
        std::string playername = "";
        PlayerSAO *playersao = NULL;
 {
        std::string playername = "";
        PlayerSAO *playersao = NULL;
-       m_clients.Lock();
+       m_clients.lock();
        try {
                RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
                if (client != NULL) {
                        playername = client->getName();
        try {
                RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
                if (client != NULL) {
                        playername = client->getName();
-                       playersao = emergePlayer(playername.c_str(), peer_id);
+                       playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
                }
        } catch (std::exception &e) {
                }
        } catch (std::exception &e) {
-               m_clients.Unlock();
+               m_clients.unlock();
                throw;
        }
                throw;
        }
-       m_clients.Unlock();
+       m_clients.unlock();
 
        RemotePlayer *player =
                static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
 
        RemotePlayer *player =
                static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
@@ -1108,7 +1102,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
        SendInventory(playersao);
 
        // Send HP
        SendInventory(playersao);
 
        // Send HP
-       SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
+       SendPlayerHPOrDie(playersao);
 
        // Send Breath
        SendPlayerBreath(peer_id);
 
        // Send Breath
        SendPlayerBreath(peer_id);
@@ -1124,16 +1118,19 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
 
                // Send information about joining in chat
                {
 
                // Send information about joining in chat
                {
-                       std::wstring name = L"unknown";
+                       std::string name = "unknown";
                        Player *player = m_env->getPlayer(peer_id);
                        if(player != NULL)
                        Player *player = m_env->getPlayer(peer_id);
                        if(player != NULL)
-                               name = narrow_to_wide(player->getName());
+                               name = player->getName();
 
                        std::wstring message;
                        message += L"*** ";
 
                        std::wstring message;
                        message += L"*** ";
-                       message += name;
+                       message += narrow_to_wide(name);
                        message += L" joined the game.";
                        SendChatMessage(PEER_ID_INEXISTENT,message);
                        message += L" joined the game.";
                        SendChatMessage(PEER_ID_INEXISTENT,message);
+                       if (m_admin_chat)
+                               m_admin_chat->outgoing_queue.push_back(
+                                       new ChatEventNick(CET_NICK_ADD, name));
                }
        }
        Address addr = getPeerAddress(player->peer_id);
                }
        }
        Address addr = getPeerAddress(player->peer_id);
@@ -1148,7 +1145,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
                actionstream<<player->getName() <<" joins game. List of players: ";
 
                for (std::vector<std::string>::iterator i = names.begin();
                actionstream<<player->getName() <<" joins game. List of players: ";
 
                for (std::vector<std::string>::iterator i = names.begin();
-                               i != names.end(); i++) {
+                               i != names.end(); ++i) {
                        actionstream << *i << " ";
                }
 
                        actionstream << *i << " ";
                }
 
@@ -1165,9 +1162,9 @@ inline void Server::handleCommand(NetworkPacket* pkt)
 
 void Server::ProcessData(NetworkPacket *pkt)
 {
 
 void Server::ProcessData(NetworkPacket *pkt)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        // Environment is locked first.
        // Environment is locked first.
-       JMutexAutoLock envlock(m_env_mutex);
+       MutexAutoLock envlock(m_env_mutex);
 
        ScopeProfiler sp(g_profiler, "Server::ProcessData");
        u32 peer_id = pkt->getPeerId();
 
        ScopeProfiler sp(g_profiler, "Server::ProcessData");
        u32 peer_id = pkt->getPeerId();
@@ -1183,7 +1180,7 @@ void Server::ProcessData(NetworkPacket *pkt)
                                        << ban_name << std::endl;
                        // This actually doesn't seem to transfer to the client
                        DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
                                        << ban_name << std::endl;
                        // This actually doesn't seem to transfer to the client
                        DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
-                                       + narrow_to_wide(ban_name));
+                                       + utf8_to_wide(ban_name));
                        return;
                }
        }
                        return;
                }
        }
@@ -1349,19 +1346,19 @@ void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
 {
        std::vector<u16> clients = m_clients.getClientIDs();
 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
 {
        std::vector<u16> clients = m_clients.getClientIDs();
-       m_clients.Lock();
+       m_clients.lock();
        // Set the modified blocks unsent for all the clients
        for (std::vector<u16>::iterator i = clients.begin();
                 i != clients.end(); ++i) {
                        if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
                                client->SetBlocksNotSent(block);
        }
        // Set the modified blocks unsent for all the clients
        for (std::vector<u16>::iterator i = clients.begin();
                 i != clients.end(); ++i) {
                        if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
                                client->SetBlocksNotSent(block);
        }
-       m_clients.Unlock();
+       m_clients.unlock();
 }
 
 void Server::peerAdded(con::Peer *peer)
 {
 }
 
 void Server::peerAdded(con::Peer *peer)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        verbosestream<<"Server::peerAdded(): peer->id="
                        <<peer->id<<std::endl;
 
        verbosestream<<"Server::peerAdded(): peer->id="
                        <<peer->id<<std::endl;
 
@@ -1374,7 +1371,7 @@ void Server::peerAdded(con::Peer *peer)
 
 void Server::deletingPeer(con::Peer *peer, bool timeout)
 {
 
 void Server::deletingPeer(con::Peer *peer, bool timeout)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        verbosestream<<"Server::deletingPeer(): peer->id="
                        <<peer->id<<", timeout="<<timeout<<std::endl;
 
        verbosestream<<"Server::deletingPeer(): peer->id="
                        <<peer->id<<", timeout="<<timeout<<std::endl;
 
@@ -1406,11 +1403,11 @@ bool Server::getClientInfo(
        )
 {
        *state = m_clients.getClientState(peer_id);
        )
 {
        *state = m_clients.getClientState(peer_id);
-       m_clients.Lock();
+       m_clients.lock();
        RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
 
        if (client == NULL) {
        RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
 
        if (client == NULL) {
-               m_clients.Unlock();
+               m_clients.unlock();
                return false;
        }
 
                return false;
        }
 
@@ -1423,7 +1420,7 @@ bool Server::getClientInfo(
        *patch = client->getPatch();
        *vers_string = client->getPatch();
 
        *patch = client->getPatch();
        *vers_string = client->getPatch();
 
-       m_clients.Unlock();
+       m_clients.unlock();
 
        return true;
 }
 
        return true;
 }
@@ -1456,6 +1453,16 @@ void Server::handlePeerChanges()
        }
 }
 
        }
 }
 
+void Server::printToConsoleOnly(const std::string &text)
+{
+       if (m_admin_chat) {
+               m_admin_chat->outgoing_queue.push_back(
+                       new ChatEventChat("", utf8_to_wide(text)));
+       } else {
+               std::cout << text << std::endl;
+       }
+}
+
 void Server::Send(NetworkPacket* pkt)
 {
        m_clients.send(pkt->getPeerId(),
 void Server::Send(NetworkPacket* pkt)
 {
        m_clients.send(pkt->getPeerId(),
@@ -1466,7 +1473,7 @@ void Server::Send(NetworkPacket* pkt)
 
 void Server::SendMovement(u16 peer_id)
 {
 
 void Server::SendMovement(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        std::ostringstream os(std::ios_base::binary);
 
        NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
        std::ostringstream os(std::ios_base::binary);
 
        NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
@@ -1487,9 +1494,23 @@ void Server::SendMovement(u16 peer_id)
        Send(&pkt);
 }
 
        Send(&pkt);
 }
 
+void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
+{
+       if (!g_settings->getBool("enable_damage"))
+               return;
+
+       u16 peer_id   = playersao->getPeerID();
+       bool is_alive = playersao->getHP() > 0;
+
+       if (is_alive)
+               SendPlayerHP(peer_id);
+       else
+               DiePlayer(peer_id);
+}
+
 void Server::SendHP(u16 peer_id, u8 hp)
 {
 void Server::SendHP(u16 peer_id, u8 hp)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
        pkt << hp;
 
        NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
        pkt << hp;
@@ -1498,29 +1519,31 @@ void Server::SendHP(u16 peer_id, u8 hp)
 
 void Server::SendBreath(u16 peer_id, u16 breath)
 {
 
 void Server::SendBreath(u16 peer_id, u16 breath)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
        pkt << (u16) breath;
        Send(&pkt);
 }
 
 
        NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
        pkt << (u16) breath;
        Send(&pkt);
 }
 
-void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
+void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
+               const std::string &custom_reason, bool reconnect)
 {
 {
-       DSTACK(__FUNCTION_NAME);
+       assert(reason < SERVER_ACCESSDENIED_MAX);
 
        NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
 
        NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
-       pkt << (u8) reason;
-
-       if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
+       pkt << (u8)reason;
+       if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
                pkt << custom_reason;
                pkt << custom_reason;
-       }
+       else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
+                       reason == SERVER_ACCESSDENIED_CRASH)
+               pkt << custom_reason << (u8)reconnect;
        Send(&pkt);
 }
 
 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
 {
        Send(&pkt);
 }
 
 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
        pkt << reason;
 
        NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
        pkt << reason;
@@ -1530,7 +1553,7 @@ void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
                v3f camera_point_target)
 {
 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
                v3f camera_point_target)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
        pkt << set_camera_point_target << camera_point_target;
 
        NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
        pkt << set_camera_point_target << camera_point_target;
@@ -1540,7 +1563,7 @@ void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
 void Server::SendItemDef(u16 peer_id,
                IItemDefManager *itemdef, u16 protocol_version)
 {
 void Server::SendItemDef(u16 peer_id,
                IItemDefManager *itemdef, u16 protocol_version)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
 
 
        NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
 
@@ -1565,7 +1588,7 @@ void Server::SendItemDef(u16 peer_id,
 void Server::SendNodeDef(u16 peer_id,
                INodeDefManager *nodedef, u16 protocol_version)
 {
 void Server::SendNodeDef(u16 peer_id,
                INodeDefManager *nodedef, u16 protocol_version)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
 
 
        NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
 
@@ -1594,7 +1617,7 @@ void Server::SendNodeDef(u16 peer_id,
 
 void Server::SendInventory(PlayerSAO* playerSAO)
 {
 
 void Server::SendInventory(PlayerSAO* playerSAO)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        UpdateCrafting(playerSAO->getPlayer());
 
 
        UpdateCrafting(playerSAO->getPlayer());
 
@@ -1615,7 +1638,7 @@ void Server::SendInventory(PlayerSAO* playerSAO)
 
 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
 {
 
 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
        pkt << message;
 
        NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
        pkt << message;
@@ -1631,7 +1654,7 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
                                      const std::string &formname)
 {
 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
                                      const std::string &formname)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
 
 
        NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
 
@@ -1646,7 +1669,7 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
                                float expirationtime, float size, bool collisiondetection,
                                bool vertical, std::string texture)
 {
                                float expirationtime, float size, bool collisiondetection,
                                bool vertical, std::string texture)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
 
 
        NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
 
@@ -1668,7 +1691,7 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
        v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
        float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
 {
        v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
        float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
 
 
        NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
 
@@ -1690,7 +1713,7 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
 
 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
 {
 
 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
 
 
        NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
 
@@ -1800,7 +1823,7 @@ void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
 
 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
 {
 
 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
        pkt << time << time_speed;
 
        NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
        pkt << time << time_speed;
@@ -1815,7 +1838,7 @@ void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
 
 void Server::SendPlayerHP(u16 peer_id)
 {
 
 void Server::SendPlayerHP(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        // In some rare case, if the player is disconnected
        // while Lua call l_punch, for example, this can be NULL
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        // In some rare case, if the player is disconnected
        // while Lua call l_punch, for example, this can be NULL
@@ -1833,7 +1856,7 @@ void Server::SendPlayerHP(u16 peer_id)
 
 void Server::SendPlayerBreath(u16 peer_id)
 {
 
 void Server::SendPlayerBreath(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        assert(playersao);
 
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        assert(playersao);
 
@@ -1843,7 +1866,7 @@ void Server::SendPlayerBreath(u16 peer_id)
 
 void Server::SendMovePlayer(u16 peer_id)
 {
 
 void Server::SendMovePlayer(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        Player *player = m_env->getPlayer(peer_id);
        assert(player);
 
        Player *player = m_env->getPlayer(peer_id);
        assert(player);
 
@@ -1895,7 +1918,7 @@ void Server::SendPlayerPrivileges(u16 peer_id)
        pkt << (u16) privs.size();
 
        for(std::set<std::string>::const_iterator i = privs.begin();
        pkt << (u16) privs.size();
 
        for(std::set<std::string>::const_iterator i = privs.begin();
-                       i != privs.end(); i++) {
+                       i != privs.end(); ++i) {
                pkt << (*i);
        }
 
                pkt << (*i);
        }
 
@@ -1995,7 +2018,7 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
                        << (u8) params.type << pos << params.object << params.loop;
 
        for(std::vector<u16>::iterator i = dst_clients.begin();
                        << (u8) params.type << pos << params.object << params.loop;
 
        for(std::vector<u16>::iterator i = dst_clients.begin();
-                       i != dst_clients.end(); i++) {
+                       i != dst_clients.end(); ++i) {
                psound.clients.insert(*i);
                m_clients.send(*i, 0, &pkt, true);
        }
                psound.clients.insert(*i);
                m_clients.send(*i, 0, &pkt, true);
        }
@@ -2014,7 +2037,7 @@ void Server::stopSound(s32 handle)
        pkt << handle;
 
        for(std::set<u16>::iterator i = psound.clients.begin();
        pkt << handle;
 
        for(std::set<u16>::iterator i = psound.clients.begin();
-                       i != psound.clients.end(); i++) {
+                       i != psound.clients.end(); ++i) {
                // Send as reliable
                m_clients.send(*i, 0, &pkt, true);
        }
                // Send as reliable
                m_clients.send(*i, 0, &pkt, true);
        }
@@ -2075,7 +2098,7 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
                }
 
                NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
                }
 
                NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
-               m_clients.Lock();
+               m_clients.lock();
                RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
                if (client != 0) {
                        pkt << p << n.param0 << n.param1 << n.param2
                RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
                if (client != 0) {
                        pkt << p << n.param0 << n.param1 << n.param2
@@ -2085,11 +2108,11 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
                                if (client->net_proto_version <= 21) {
                                        // Old clients always clear metadata; fix it
                                        // by sending the full block again.
                                if (client->net_proto_version <= 21) {
                                        // Old clients always clear metadata; fix it
                                        // by sending the full block again.
-                                       client->SetBlockNotSent(p);
+                                       client->SetBlockNotSent(getNodeBlockPos(p));
                                }
                        }
                }
                                }
                        }
                }
-               m_clients.Unlock();
+               m_clients.unlock();
 
                // Send as reliable
                if (pkt.getSize() > 0)
 
                // Send as reliable
                if (pkt.getSize() > 0)
@@ -2100,18 +2123,18 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
 void Server::setBlockNotSent(v3s16 p)
 {
        std::vector<u16> clients = m_clients.getClientIDs();
 void Server::setBlockNotSent(v3s16 p)
 {
        std::vector<u16> clients = m_clients.getClientIDs();
-       m_clients.Lock();
+       m_clients.lock();
        for(std::vector<u16>::iterator i = clients.begin();
                i != clients.end(); ++i) {
                RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
                client->SetBlockNotSent(p);
        }
        for(std::vector<u16>::iterator i = clients.begin();
                i != clients.end(); ++i) {
                RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
                client->SetBlockNotSent(p);
        }
-       m_clients.Unlock();
+       m_clients.unlock();
 }
 
 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
 {
 }
 
 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        v3s16 p = block->getPos();
 
 
        v3s16 p = block->getPos();
 
@@ -2133,9 +2156,9 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto
 
 void Server::SendBlocks(float dtime)
 {
 
 void Server::SendBlocks(float dtime)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
 
-       JMutexAutoLock envlock(m_env_mutex);
+       MutexAutoLock envlock(m_env_mutex);
        //TODO check if one big lock could be faster then multiple small ones
 
        ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
        //TODO check if one big lock could be faster then multiple small ones
 
        ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
@@ -2149,7 +2172,7 @@ void Server::SendBlocks(float dtime)
 
                std::vector<u16> clients = m_clients.getClientIDs();
 
 
                std::vector<u16> clients = m_clients.getClientIDs();
 
-               m_clients.Lock();
+               m_clients.lock();
                for(std::vector<u16>::iterator i = clients.begin();
                        i != clients.end(); ++i) {
                        RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
                for(std::vector<u16>::iterator i = clients.begin();
                        i != clients.end(); ++i) {
                        RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
@@ -2160,7 +2183,7 @@ void Server::SendBlocks(float dtime)
                        total_sending += client->SendingCount();
                        client->GetNextBlocks(m_env,m_emerge, dtime, queue);
                }
                        total_sending += client->SendingCount();
                        client->GetNextBlocks(m_env,m_emerge, dtime, queue);
                }
-               m_clients.Unlock();
+               m_clients.unlock();
        }
 
        // Sort.
        }
 
        // Sort.
@@ -2168,7 +2191,7 @@ void Server::SendBlocks(float dtime)
        // Lowest is most important.
        std::sort(queue.begin(), queue.end());
 
        // Lowest is most important.
        std::sort(queue.begin(), queue.end());
 
-       m_clients.Lock();
+       m_clients.lock();
        for(u32 i=0; i<queue.size(); i++)
        {
                //TODO: Calculate limit dynamically
        for(u32 i=0; i<queue.size(); i++)
        {
                //TODO: Calculate limit dynamically
@@ -2198,19 +2221,19 @@ void Server::SendBlocks(float dtime)
                client->SentBlock(q.pos);
                total_sending++;
        }
                client->SentBlock(q.pos);
                total_sending++;
        }
-       m_clients.Unlock();
+       m_clients.unlock();
 }
 
 void Server::fillMediaCache()
 {
 }
 
 void Server::fillMediaCache()
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        infostream<<"Server: Calculating media file checksums"<<std::endl;
 
        // Collect all media file paths
        std::vector<std::string> paths;
        for(std::vector<ModSpec>::iterator i = m_mods.begin();
 
        infostream<<"Server: Calculating media file checksums"<<std::endl;
 
        // Collect all media file paths
        std::vector<std::string> paths;
        for(std::vector<ModSpec>::iterator i = m_mods.begin();
-                       i != m_mods.end(); i++) {
+                       i != m_mods.end(); ++i) {
                const ModSpec &mod = *i;
                paths.push_back(mod.path + DIR_DELIM + "textures");
                paths.push_back(mod.path + DIR_DELIM + "sounds");
                const ModSpec &mod = *i;
                paths.push_back(mod.path + DIR_DELIM + "textures");
                paths.push_back(mod.path + DIR_DELIM + "sounds");
@@ -2221,7 +2244,7 @@ void Server::fillMediaCache()
 
        // Collect media file information from paths into cache
        for(std::vector<std::string>::iterator i = paths.begin();
 
        // Collect media file information from paths into cache
        for(std::vector<std::string>::iterator i = paths.begin();
-                       i != paths.end(); i++) {
+                       i != paths.end(); ++i) {
                std::string mediapath = *i;
                std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
                for (u32 j = 0; j < dirlist.size(); j++) {
                std::string mediapath = *i;
                std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
                for (u32 j = 0; j < dirlist.size(); j++) {
@@ -2297,44 +2320,22 @@ void Server::fillMediaCache()
        }
 }
 
        }
 }
 
-struct SendableMediaAnnouncement
-{
-       std::string name;
-       std::string sha1_digest;
-
-       SendableMediaAnnouncement(const std::string &name_="",
-                                 const std::string &sha1_digest_=""):
-               name(name_),
-               sha1_digest(sha1_digest_)
-       {}
-};
-
 void Server::sendMediaAnnouncement(u16 peer_id)
 {
 void Server::sendMediaAnnouncement(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
-
-       verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
-                       <<std::endl;
-
-       std::vector<SendableMediaAnnouncement> file_announcements;
+       DSTACK(FUNCTION_NAME);
 
 
-       for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
-                       i != m_media.end(); i++){
-               // Put in list
-               file_announcements.push_back(
-                               SendableMediaAnnouncement(i->first, i->second.sha1_digest));
-       }
+       verbosestream << "Server: Announcing files to id(" << peer_id << ")"
+               << std::endl;
 
        // Make packet
        std::ostringstream os(std::ios_base::binary);
 
        NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
 
        // Make packet
        std::ostringstream os(std::ios_base::binary);
 
        NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
-       pkt << (u16) file_announcements.size();
+       pkt << (u16) m_media.size();
 
 
-       for (std::vector<SendableMediaAnnouncement>::iterator
-                       j = file_announcements.begin();
-                       j != file_announcements.end(); ++j) {
-               pkt << j->name << j->sha1_digest;
+       for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
+                       i != m_media.end(); ++i) {
+               pkt << i->first << i->second.sha1_digest;
        }
 
        pkt << g_settings->get("remote_media");
        }
 
        pkt << g_settings->get("remote_media");
@@ -2358,7 +2359,7 @@ struct SendableMedia
 void Server::sendRequestedMedia(u16 peer_id,
                const std::vector<std::string> &tosend)
 {
 void Server::sendRequestedMedia(u16 peer_id,
                const std::vector<std::string> &tosend)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        verbosestream<<"Server::sendRequestedMedia(): "
                        <<"Sending files to client"<<std::endl;
 
        verbosestream<<"Server::sendRequestedMedia(): "
                        <<"Sending files to client"<<std::endl;
@@ -2465,7 +2466,7 @@ void Server::sendRequestedMedia(u16 peer_id,
 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
 {
        if(m_detached_inventories.count(name) == 0) {
 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
 {
        if(m_detached_inventories.count(name) == 0) {
-               errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
+               errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
                return;
        }
        Inventory *inv = m_detached_inventories[name];
                return;
        }
        Inventory *inv = m_detached_inventories[name];
@@ -2490,11 +2491,11 @@ void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
 
 void Server::sendDetachedInventories(u16 peer_id)
 {
 
 void Server::sendDetachedInventories(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        for(std::map<std::string, Inventory*>::iterator
                        i = m_detached_inventories.begin();
 
        for(std::map<std::string, Inventory*>::iterator
                        i = m_detached_inventories.begin();
-                       i != m_detached_inventories.end(); i++) {
+                       i != m_detached_inventories.end(); ++i) {
                const std::string &name = i->first;
                //Inventory *inv = i->second;
                sendDetachedInventory(name, peer_id);
                const std::string &name = i->first;
                //Inventory *inv = i->second;
                sendDetachedInventory(name, peer_id);
@@ -2507,7 +2508,7 @@ void Server::sendDetachedInventories(u16 peer_id)
 
 void Server::DiePlayer(u16 peer_id)
 {
 
 void Server::DiePlayer(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        assert(playersao);
 
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        assert(playersao);
@@ -2527,7 +2528,7 @@ void Server::DiePlayer(u16 peer_id)
 
 void Server::RespawnPlayer(u16 peer_id)
 {
 
 void Server::RespawnPlayer(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        assert(playersao);
 
        PlayerSAO *playersao = getPlayerSAO(peer_id);
        assert(playersao);
@@ -2549,17 +2550,37 @@ void Server::RespawnPlayer(u16 peer_id)
                playersao->setPos(pos);
        }
 }
                playersao->setPos(pos);
        }
 }
+
+
 void Server::DenySudoAccess(u16 peer_id)
 {
 void Server::DenySudoAccess(u16 peer_id)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
        Send(&pkt);
 }
 
 
        NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
        Send(&pkt);
 }
 
+
+void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
+               const std::string &str_reason, bool reconnect)
+{
+       if (proto_ver >= 25) {
+               SendAccessDenied(peer_id, reason, str_reason);
+       } else {
+               std::wstring wreason = utf8_to_wide(
+                       reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
+                       accessDeniedStrings[(u8)reason]);
+               SendAccessDenied_Legacy(peer_id, wreason);
+       }
+
+       m_clients.event(peer_id, CSE_SetDenied);
+       m_con.DisconnectPeer(peer_id);
+}
+
+
 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
 {
 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        SendAccessDenied(peer_id, reason, custom_reason);
        m_clients.event(peer_id, CSE_SetDenied);
 
        SendAccessDenied(peer_id, reason, custom_reason);
        m_clients.event(peer_id, CSE_SetDenied);
@@ -2570,7 +2591,7 @@ void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string
 // the minimum version for MT users, maybe in 1 year
 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
 {
 // the minimum version for MT users, maybe in 1 year
 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        SendAccessDenied_Legacy(peer_id, reason);
        m_clients.event(peer_id, CSE_SetDenied);
 
        SendAccessDenied_Legacy(peer_id, reason);
        m_clients.event(peer_id, CSE_SetDenied);
@@ -2579,7 +2600,7 @@ void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
 
 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
 {
 
 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        if (!forSudoMode) {
                RemoteClient* client = getClient(peer_id, CS_Invalid);
 
        if (!forSudoMode) {
                RemoteClient* client = getClient(peer_id, CS_Invalid);
@@ -2610,7 +2631,7 @@ void Server::acceptAuth(u16 peer_id, bool forSudoMode)
 
 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
 {
 
 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        std::wstring message;
        {
                /*
        std::wstring message;
        {
                /*
@@ -2625,7 +2646,7 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
                        if(psound.clients.empty())
                                m_playing_sounds.erase(i++);
                        else
                        if(psound.clients.empty())
                                m_playing_sounds.erase(i++);
                        else
-                               i++;
+                               ++i;
                }
 
                Player *player = m_env->getPlayer(peer_id);
                }
 
                Player *player = m_env->getPlayer(peer_id);
@@ -2675,13 +2696,17 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
                                        os << player->getName() << " ";
                                }
 
                                        os << player->getName() << " ";
                                }
 
-                               actionstream << player->getName() << " "
+                               std::string name = player->getName();
+                               actionstream << name << " "
                                                << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
                                                << " List of players: " << os.str() << std::endl;
                                                << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
                                                << " List of players: " << os.str() << std::endl;
+                               if (m_admin_chat)
+                                       m_admin_chat->outgoing_queue.push_back(
+                                               new ChatEventNick(CET_NICK_REMOVE, name));
                        }
                }
                {
                        }
                }
                {
-                       JMutexAutoLock env_lock(m_env_mutex);
+                       MutexAutoLock env_lock(m_env_mutex);
                        m_clients.DeleteClient(peer_id);
                }
        }
                        m_clients.DeleteClient(peer_id);
                }
        }
@@ -2693,7 +2718,7 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
 
 void Server::UpdateCrafting(Player* player)
 {
 
 void Server::UpdateCrafting(Player* player)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        // Get a preview for crafting
        ItemStack preview;
 
        // Get a preview for crafting
        ItemStack preview;
@@ -2710,6 +2735,102 @@ void Server::UpdateCrafting(Player* player)
        plist->changeItem(0, preview);
 }
 
        plist->changeItem(0, preview);
 }
 
+void Server::handleChatInterfaceEvent(ChatEvent *evt)
+{
+       if (evt->type == CET_NICK_ADD) {
+               // The terminal informed us of its nick choice
+               m_admin_nick = ((ChatEventNick *)evt)->nick;
+               if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
+                       errorstream << "You haven't set up an account." << std::endl
+                               << "Please log in using the client as '"
+                               << m_admin_nick << "' with a secure password." << std::endl
+                               << "Until then, you can't execute admin tasks via the console," << std::endl
+                               << "and everybody can claim the user account instead of you," << std::endl
+                               << "giving them full control over this server." << std::endl;
+               }
+       } else {
+               assert(evt->type == CET_CHAT);
+               handleAdminChat((ChatEventChat *)evt);
+       }
+}
+
+std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
+       const std::wstring &wmessage, bool check_shout_priv,
+       u16 peer_id_to_avoid_sending)
+{
+       // If something goes wrong, this player is to blame
+       RollbackScopeActor rollback_scope(m_rollback,
+               std::string("player:") + name);
+
+       // Line to send
+       std::wstring line;
+       // Whether to send line to the player that sent the message, or to all players
+       bool broadcast_line = true;
+
+       // Run script hook
+       bool ate = m_script->on_chat_message(name,
+               wide_to_utf8(wmessage));
+       // If script ate the message, don't proceed
+       if (ate)
+               return L"";
+
+       // Commands are implemented in Lua, so only catch invalid
+       // commands that were not "eaten" and send an error back
+       if (wmessage[0] == L'/') {
+               std::wstring wcmd = wmessage.substr(1);
+               broadcast_line = false;
+               if (wcmd.length() == 0)
+                       line += L"-!- Empty command";
+               else
+                       line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
+       } else {
+               if (check_shout_priv && !checkPriv(name, "shout")) {
+                       line += L"-!- You don't have permission to shout.";
+                       broadcast_line = false;
+               } else {
+                       line += L"<";
+                       line += wname;
+                       line += L"> ";
+                       line += wmessage;
+               }
+       }
+
+       /*
+               Tell calling method to send the message to sender
+       */
+       if (!broadcast_line) {
+               return line;
+       } else {
+               /*
+                       Send the message to others
+               */
+               actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
+
+               std::vector<u16> clients = m_clients.getClientIDs();
+
+               for (u16 i = 0; i < clients.size(); i++) {
+                       u16 cid = clients[i];
+                       if (cid != peer_id_to_avoid_sending)
+                               SendChatMessage(cid, line);
+               }
+       }
+       return L"";
+}
+
+void Server::handleAdminChat(const ChatEventChat *evt)
+{
+       std::string name = evt->nick;
+       std::wstring wname = utf8_to_wide(name);
+       std::wstring wmessage = evt->evt_msg;
+
+       std::wstring answer = handleChat(name, wname, wmessage);
+
+       // If asked to send answer to sender
+       if (!answer.empty()) {
+               m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
+       }
+}
+
 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
 {
        RemoteClient *client = getClientNoEx(peer_id,state_min);
 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
 {
        RemoteClient *client = getClientNoEx(peer_id,state_min);
@@ -2837,9 +2958,18 @@ std::string Server::getBanDescription(const std::string &ip_or_name)
 
 void Server::notifyPlayer(const char *name, const std::wstring &msg)
 {
 
 void Server::notifyPlayer(const char *name, const std::wstring &msg)
 {
+       // m_env will be NULL if the server is initializing
+       if (!m_env)
+               return;
+
+       if (m_admin_nick == name && !m_admin_nick.empty()) {
+               m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
+       }
+
        Player *player = m_env->getPlayer(name);
        Player *player = m_env->getPlayer(name);
-       if (!player)
+       if (!player) {
                return;
                return;
+       }
 
        if (player->peer_id == PEER_ID_INEXISTENT)
                return;
 
        if (player->peer_id == PEER_ID_INEXISTENT)
                return;
@@ -2850,6 +2980,10 @@ void Server::notifyPlayer(const char *name, const std::wstring &msg)
 bool Server::showFormspec(const char *playername, const std::string &formspec,
        const std::string &formname)
 {
 bool Server::showFormspec(const char *playername, const std::string &formspec,
        const std::string &formname)
 {
+       // m_env will be NULL if the server is initializing
+       if (!m_env)
+               return false;
+
        Player *player = m_env->getPlayer(playername);
        if (!player)
                return false;
        Player *player = m_env->getPlayer(playername);
        if (!player)
                return false;
@@ -2900,7 +3034,8 @@ bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
                return false;
 
        SendHUDSetFlags(player->peer_id, flags, mask);
                return false;
 
        SendHUDSetFlags(player->peer_id, flags, mask);
-       player->hud_flags = flags;
+       player->hud_flags &= ~mask;
+       player->hud_flags |= flags;
 
        PlayerSAO* playersao = player->getPlayerSAO();
 
 
        PlayerSAO* playersao = player->getPlayerSAO();
 
@@ -3014,64 +3149,45 @@ void Server::notifyPlayers(const std::wstring &msg)
        SendChatMessage(PEER_ID_INEXISTENT,msg);
 }
 
        SendChatMessage(PEER_ID_INEXISTENT,msg);
 }
 
-void Server::spawnParticle(const char *playername, v3f pos,
+void Server::spawnParticle(const std::string &playername, v3f pos,
        v3f velocity, v3f acceleration,
        float expirationtime, float size, bool
        collisiondetection, bool vertical, const std::string &texture)
 {
        v3f velocity, v3f acceleration,
        float expirationtime, float size, bool
        collisiondetection, bool vertical, const std::string &texture)
 {
-       Player *player = m_env->getPlayer(playername);
-       if(!player)
+       // m_env will be NULL if the server is initializing
+       if (!m_env)
                return;
                return;
-       SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
-                       expirationtime, size, collisiondetection, vertical, texture);
-}
 
 
-void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
-       float expirationtime, float size,
-       bool collisiondetection, bool vertical, const std::string &texture)
-{
-       SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
+       u16 peer_id = PEER_ID_INEXISTENT;
+       if (playername != "") {
+               Player* player = m_env->getPlayer(playername.c_str());
+               if (!player)
+                       return;
+               peer_id = player->peer_id;
+       }
+
+       SendSpawnParticle(peer_id, pos, velocity, acceleration,
                        expirationtime, size, collisiondetection, vertical, texture);
 }
 
                        expirationtime, size, collisiondetection, vertical, texture);
 }
 
-u32 Server::addParticleSpawner(const char *playername, u16 amount, float spawntime,
+u32 Server::addParticleSpawner(u16 amount, float spawntime,
        v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
        float minexptime, float maxexptime, float minsize, float maxsize,
        v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
        float minexptime, float maxexptime, float minsize, float maxsize,
-       bool collisiondetection, bool vertical, const std::string &texture)
+       bool collisiondetection, bool vertical, const std::string &texture,
+       const std::string &playername)
 {
 {
-       Player *player = m_env->getPlayer(playername);
-       if(!player)
+       // m_env will be NULL if the server is initializing
+       if (!m_env)
                return -1;
 
                return -1;
 
-       u32 id = 0;
-       for(;;) // look for unused particlespawner id
-       {
-               id++;
-               if (std::find(m_particlespawner_ids.begin(),
-                               m_particlespawner_ids.end(), id)
-                               == m_particlespawner_ids.end())
-               {
-                       m_particlespawner_ids.push_back(id);
-                       break;
-               }
+       u16 peer_id = PEER_ID_INEXISTENT;
+       if (playername != "") {
+               Player* player = m_env->getPlayer(playername.c_str());
+               if (!player)
+                       return -1;
+               peer_id = player->peer_id;
        }
 
        }
 
-       SendAddParticleSpawner(player->peer_id, amount, spawntime,
-               minpos, maxpos, minvel, maxvel, minacc, maxacc,
-               minexptime, maxexptime, minsize, maxsize,
-               collisiondetection, vertical, texture, id);
-
-       return id;
-}
-
-u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
-       v3f minpos, v3f maxpos,
-       v3f minvel, v3f maxvel,
-       v3f minacc, v3f maxacc,
-       float minexptime, float maxexptime,
-       float minsize, float maxsize,
-       bool collisiondetection, bool vertical, const std::string &texture)
-{
        u32 id = 0;
        for(;;) // look for unused particlespawner id
        {
        u32 id = 0;
        for(;;) // look for unused particlespawner id
        {
@@ -3085,7 +3201,7 @@ u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
                }
        }
 
                }
        }
 
-       SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
+       SendAddParticleSpawner(peer_id, amount, spawntime,
                minpos, maxpos, minvel, maxvel, minacc, maxacc,
                minexptime, maxexptime, minsize, maxsize,
                collisiondetection, vertical, texture, id);
                minpos, maxpos, minvel, maxvel, minacc, maxacc,
                minexptime, maxexptime, minsize, maxsize,
                collisiondetection, vertical, texture, id);
@@ -3093,26 +3209,25 @@ u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
        return id;
 }
 
        return id;
 }
 
-void Server::deleteParticleSpawner(const char *playername, u32 id)
+void Server::deleteParticleSpawner(const std::string &playername, u32 id)
 {
 {
-       Player *player = m_env->getPlayer(playername);
-       if(!player)
-               return;
+       // m_env will be NULL if the server is initializing
+       if (!m_env)
+               throw ServerError("Can't delete particle spawners during initialisation!");
 
 
-       m_particlespawner_ids.erase(
-                       std::remove(m_particlespawner_ids.begin(),
-                       m_particlespawner_ids.end(), id),
-                       m_particlespawner_ids.end());
-       SendDeleteParticleSpawner(player->peer_id, id);
-}
+       u16 peer_id = PEER_ID_INEXISTENT;
+       if (playername != "") {
+               Player* player = m_env->getPlayer(playername.c_str());
+               if (!player)
+                       return;
+               peer_id = player->peer_id;
+       }
 
 
-void Server::deleteParticleSpawnerAll(u32 id)
-{
        m_particlespawner_ids.erase(
                        std::remove(m_particlespawner_ids.begin(),
                        m_particlespawner_ids.end(), id),
                        m_particlespawner_ids.end());
        m_particlespawner_ids.erase(
                        std::remove(m_particlespawner_ids.begin(),
                        m_particlespawner_ids.end(), id),
                        m_particlespawner_ids.end());
-       SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
+       SendDeleteParticleSpawner(peer_id, id);
 }
 
 Inventory* Server::createDetachedInventory(const std::string &name)
 }
 
 Inventory* Server::createDetachedInventory(const std::string &name)
@@ -3150,7 +3265,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
 
        for(std::list<RollbackAction>::const_iterator
                        i = actions.begin();
 
        for(std::list<RollbackAction>::const_iterator
                        i = actions.begin();
-                       i != actions.end(); i++)
+                       i != actions.end(); ++i)
        {
                const RollbackAction &action = *i;
                num_tried++;
        {
                const RollbackAction &action = *i;
                num_tried++;
@@ -3268,30 +3383,24 @@ v3f Server::findSpawnPos()
                return nodeposf * BS;
        }
 
                return nodeposf * BS;
        }
 
-       // Default position is static_spawnpoint
-       // We will return it if we don't found a good place
-       v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
-
-       s16 water_level = map.getWaterLevel();
-
        bool is_good = false;
 
        // Try to find a good place a few times
        bool is_good = false;
 
        // Try to find a good place a few times
-       for(s32 i = 0; i < 1000 && !is_good; i++) {
+       for(s32 i = 0; i < 4000 && !is_good; i++) {
                s32 range = 1 + i;
                // We're going to try to throw the player to this position
                v2s16 nodepos2d = v2s16(
                                -range + (myrand() % (range * 2)),
                                -range + (myrand() % (range * 2)));
 
                s32 range = 1 + i;
                // We're going to try to throw the player to this position
                v2s16 nodepos2d = v2s16(
                                -range + (myrand() % (range * 2)),
                                -range + (myrand() % (range * 2)));
 
-               // Get ground height at point
-               s16 groundheight = map.findGroundLevel(nodepos2d);
-               if (groundheight <= water_level) // Don't go underwater
-                       continue;
-               if (groundheight > water_level + 6) // Don't go to high places
+               // Get spawn level at point
+               s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
+               // Continue if MAX_MAP_GENERATION_LIMIT was returned by
+               // the mapgen to signify an unsuitable spawn position
+               if (spawn_level == MAX_MAP_GENERATION_LIMIT)
                        continue;
 
                        continue;
 
-               nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
+               v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
 
                s32 air_count = 0;
                for (s32 i = 0; i < 10; i++) {
 
                s32 air_count = 0;
                for (s32 i = 0; i < 10; i++) {
@@ -3300,7 +3409,11 @@ v3f Server::findSpawnPos()
                        content_t c = map.getNodeNoEx(nodepos).getContent();
                        if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
                                air_count++;
                        content_t c = map.getNodeNoEx(nodepos).getContent();
                        if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
                                air_count++;
-                               if (air_count >= 2){
+                               if (air_count >= 2) {
+                                       nodeposf = intToFloat(nodepos, BS);
+                                       // Don't spawn the player outside map boundaries
+                                       if (objectpos_over_limit(nodeposf))
+                                               continue;
                                        is_good = true;
                                        break;
                                }
                                        is_good = true;
                                        break;
                                }
@@ -3309,10 +3422,10 @@ v3f Server::findSpawnPos()
                }
        }
 
                }
        }
 
-       return intToFloat(nodepos, BS);
+       return nodeposf;
 }
 
 }
 
-PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
+PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
 {
        bool newplayer = false;
 
 {
        bool newplayer = false;
 
@@ -3358,6 +3471,16 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
 
                // Add player to environment
                m_env->addPlayer(player);
 
                // Add player to environment
                m_env->addPlayer(player);
+       } else {
+               // If the player exists, ensure that they respawn inside legal bounds
+               // This fixes an assert crash when the player can't be added
+               // to the environment
+               if (objectpos_over_limit(player->getPosition())) {
+                       actionstream << "Respawn position for player \""
+                               << name << "\" outside limits, resetting" << std::endl;
+                       v3f pos = findSpawnPos();
+                       player->setPosition(pos);
+               }
        }
 
        // Create a new player active object
        }
 
        // Create a new player active object
@@ -3365,6 +3488,8 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
                        getPlayerEffectivePrivs(player->getName()),
                        isSingleplayer());
 
                        getPlayerEffectivePrivs(player->getName()),
                        isSingleplayer());
 
+       player->protocol_version = proto_version;
+
        /* Clean up old HUD elements from previous sessions */
        player->clearHud();
 
        /* Clean up old HUD elements from previous sessions */
        player->clearHud();
 
@@ -3381,7 +3506,7 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
 
 void dedicated_server_loop(Server &server, bool &kill)
 {
 
 void dedicated_server_loop(Server &server, bool &kill)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        verbosestream<<"dedicated_server_loop()"<<std::endl;
 
 
        verbosestream<<"dedicated_server_loop()"<<std::endl;