]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/server.cpp
Fix doc and forceloading crash.
[dragonfireclient.git] / src / server.cpp
index 7926b879fb7815fa9185e57db7192bfd18e38f78..b257448a1c4e2de8b1b7091ffd74e103352e4c2a 100644 (file)
@@ -22,19 +22,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <queue>
 #include <algorithm>
 #include "clientserver.h"
+#include "ban.h"
+#include "environment.h"
 #include "map.h"
-#include "jmutexautolock.h"
+#include "jthread/jmutexautolock.h"
 #include "main.h"
 #include "constants.h"
 #include "voxel.h"
 #include "config.h"
+#include "version.h"
 #include "filesys.h"
 #include "mapblock.h"
 #include "serverobject.h"
+#include "genericobject.h"
 #include "settings.h"
 #include "profiler.h"
 #include "log.h"
-#include "script/cpp_api/scriptapi.h"
+#include "scripting_game.h"
 #include "nodedef.h"
 #include "itemdef.h"
 #include "craftdef.h"
@@ -58,6 +62,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/mathconstants.h"
 #include "rollback.h"
 #include "util/serialize.h"
+#include "util/thread.h"
 #include "defaultsettings.h"
 
 class ClientNotFoundException : public BaseException
@@ -68,17 +73,33 @@ class ClientNotFoundException : public BaseException
        {}
 };
 
-void * ServerThread::Thread()
+class ServerThread : public JThread
 {
-       ThreadStarted();
+       Server *m_server;
+
+public:
+
+       ServerThread(Server *server):
+               JThread(),
+               m_server(server)
+       {
+       }
 
+       void * Thread();
+};
+
+void * ServerThread::Thread()
+{
        log_register_thread("ServerThread");
 
        DSTACK(__FUNCTION_NAME);
-
        BEGIN_DEBUG_EXCEPTION_HANDLER
 
-       while(getRun())
+       m_server->AsyncRunStep(true);
+
+       ThreadStarted();
+
+       while(!StopRequested())
        {
                try{
                        //TimeTaker timer("AsyncRunStep() + Receive()");
@@ -613,46 +634,23 @@ void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
        }
 }
 
-/*
-       PlayerInfo
-*/
-
-PlayerInfo::PlayerInfo()
-{
-       name[0] = 0;
-       avg_rtt = 0;
-}
-
-void PlayerInfo::PrintLine(std::ostream *s)
-{
-       (*s)<<id<<": ";
-       (*s)<<"\""<<name<<"\" ("
-                       <<(position.X/10)<<","<<(position.Y/10)
-                       <<","<<(position.Z/10)<<") ";
-       address.print(s);
-       (*s)<<" avg_rtt="<<avg_rtt;
-       (*s)<<std::endl;
-}
-
 /*
        Server
 */
 
 Server::Server(
                const std::string &path_world,
-               const std::string &path_config,
                const SubgameSpec &gamespec,
                bool simple_singleplayer_mode
        ):
        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,
              g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
-       m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
+       m_banmanager(NULL),
        m_rollback(NULL),
        m_rollback_sink_enabled(true),
        m_enable_rollback_recording(false),
@@ -662,7 +660,7 @@ Server::Server(
        m_nodedef(createNodeDefManager()),
        m_craftdef(createCraftDefManager()),
        m_event(new EventManager()),
-       m_thread(this),
+       m_thread(NULL),
        m_time_of_day_send_timer(0),
        m_uptime(0),
        m_shutdown_requested(false),
@@ -676,12 +674,9 @@ Server::Server(
        m_objectdata_timer = 0.0;
        m_emergethread_trigger_timer = 0.0;
        m_savemap_timer = 0.0;
-       m_clients_number = 0;
 
-       m_env_mutex.Init();
-       m_con_mutex.Init();
-       m_step_dtime_mutex.Init();
        m_step_dtime = 0.0;
+       m_lag = g_settings->getFloat("dedicated_server_step");
 
        if(path_world == "")
                throw ServerError("Supplied empty world path");
@@ -695,7 +690,6 @@ Server::Server(
        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;
 
        // Initialize default settings and override defaults with those provided
@@ -704,23 +698,30 @@ Server::Server(
        Settings gamedefaults;
        getGameMinetestConfig(gamespec.path, gamedefaults);
        override_default_settings(g_settings, &gamedefaults);
-       
+
+       // Create server thread
+       m_thread = new ServerThread(this);
+
        // Create emerge manager
        m_emerge = new EmergeManager(this);
-       
-       // Create rollback manager
-       std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
-       m_rollback = createRollbackManager(rollback_path, this);
 
        // Create world if it doesn't exist
        if(!initializeWorld(m_path_world, m_gamespec.id))
                throw ServerError("Failed to initialize world");
 
+       // Create ban manager
+       std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
+       m_banmanager = new BanManager(ban_path);
+
+       // Create rollback manager
+       std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
+       m_rollback = createRollbackManager(rollback_path, this);
+
        ModConfiguration modconf(m_path_world);
        m_mods = modconf.getMods();
        std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
        // complain about mods with unsatisfied dependencies
-       if(!modconf.isConsistent())     
+       if(!modconf.isConsistent())
        {
                for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
                        it != unsatisfied_mods.end(); ++it)
@@ -739,10 +740,10 @@ Server::Server(
        worldmt_settings.readConfigFile(worldmt.c_str());
        std::vector<std::string> names = worldmt_settings.getNames();
        std::set<std::string> load_mod_names;
-       for(std::vector<std::string>::iterator it = names.begin(); 
+       for(std::vector<std::string>::iterator it = names.begin();
                it != names.end(); ++it)
-       {       
-               std::string name = *it;  
+       {
+               std::string name = *it;
                if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
                        load_mod_names.insert(name.substr(9));
        }
@@ -754,7 +755,7 @@ Server::Server(
                        it != unsatisfied_mods.end(); ++it)
                load_mod_names.erase((*it).name);
        if(!load_mod_names.empty())
-       {               
+       {
                errorstream << "The following mods could not be found:";
                for(std::set<std::string>::iterator it = load_mod_names.begin();
                        it != load_mod_names.end(); ++it)
@@ -773,7 +774,7 @@ Server::Server(
 
        infostream<<"Server: Initializing Lua"<<std::endl;
 
-       m_script = new ScriptApi(this);
+       m_script = new GameScripting(this);
 
 
        // Load and run builtin.lua
@@ -816,7 +817,7 @@ Server::Server(
 
        // Initialize Environment
        ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
-       m_env = new ServerEnvironment(servermap, m_script, this, this);
+       m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
        
        // Run some callbacks after the MG params have been set up but before activation
        MapgenParams *mgparams = servermap->getMapgenParams();
@@ -824,6 +825,7 @@ Server::Server(
        
        // Initialize mapgens
        m_emerge->initMapgens(mgparams);
+       servermap->setMapgenParams(m_emerge->params);
 
        // Give environment reference to scripting api
        m_script->initializeEnvironment(m_env);
@@ -913,6 +915,7 @@ Server::~Server()
                Stop threads
        */
        stop();
+       delete m_thread;
 
        //shutdown all emerge threads first!
        delete m_emerge;
@@ -936,6 +939,7 @@ Server::~Server()
        // Delete things in the reverse order of creation
        delete m_env;
        delete m_rollback;
+       delete m_banmanager;
        delete m_event;
        delete m_itemdef;
        delete m_nodedef;
@@ -961,15 +965,14 @@ void Server::start(unsigned short port)
        infostream<<"Starting server on port "<<port<<"..."<<std::endl;
 
        // Stop thread if already running
-       m_thread.stop();
+       m_thread->Stop();
 
        // Initialize connection
        m_con.SetTimeoutMs(30);
        m_con.Serve(port);
 
        // Start thread
-       m_thread.setRun(true);
-       m_thread.Start();
+       m_thread->Start();
 
        // ASCII art for the win!
        actionstream
@@ -991,9 +994,9 @@ void Server::stop()
        infostream<<"Server: Stopping and waiting threads"<<std::endl;
 
        // Stop threads (set run=false first so both start stopping)
-       m_thread.setRun(false);
+       m_thread->Stop();
        //m_emergethread.setRun(false);
-       m_thread.stop();
+       m_thread->Wait();
        //m_emergethread.stop();
 
        infostream<<"Server: Threads stopped"<<std::endl;
@@ -1016,7 +1019,7 @@ void Server::step(float dtime)
        }
 }
 
-void Server::AsyncRunStep()
+void Server::AsyncRunStep(bool initial_step)
 {
        DSTACK(__FUNCTION_NAME);
 
@@ -1033,7 +1036,7 @@ void Server::AsyncRunStep()
                SendBlocks(dtime);
        }
 
-       if(dtime < 0.001)
+       if((dtime < 0.001) && (initial_step == false))
                return;
 
        g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
@@ -1086,15 +1089,15 @@ void Server::AsyncRunStep()
                        //JMutexAutoLock envlock(m_env_mutex);
                        JMutexAutoLock conlock(m_con_mutex);
 
+                       u16 time = m_env->getTimeOfDay();
+                       float time_speed = g_settings->getFloat("time_speed");
+
                        for(std::map<u16, RemoteClient*>::iterator
                                i = m_clients.begin();
                                i != m_clients.end(); ++i)
                        {
                                RemoteClient *client = i->second;
-                               SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
-                                               m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
-                               // Send as reliable
-                               m_con.Send(client->peer_id, 0, data, true);
+                               SendTimeOfDay(client->peer_id, time, time_speed);
                        }
                }
        }
@@ -1239,7 +1242,7 @@ void Server::AsyncRunStep()
                        counter = 0.0;
 
                        JMutexAutoLock lock2(m_con_mutex);
-                       m_clients_number = 0;
+                       m_clients_names.clear();
                        if(m_clients.size() != 0)
                                infostream<<"Players:"<<std::endl;
                        for(std::map<u16, RemoteClient*>::iterator
@@ -1253,19 +1256,20 @@ void Server::AsyncRunStep()
                                        continue;
                                infostream<<"* "<<player->getName()<<"\t";
                                client->PrintInfo(infostream);
-                               ++m_clients_number;
+                               m_clients_names.push_back(player->getName());
                        }
                }
        }
 
 
+       m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
 #if USE_CURL
        // send masterserver announce
        {
                float &counter = m_masterserver_timer;
                if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
                {
-                       ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
+                       ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_names, m_uptime.get(), m_env->getGameTime(), m_lag, m_gamespec.id, m_mods);
                        counter = 0.01;
                }
                counter += dtime;
@@ -1525,7 +1529,7 @@ void Server::AsyncRunStep()
                                memcpy((char*)&reply[2], unreliable_data.c_str(),
                                                unreliable_data.size());
                                // Send as unreliable
-                               m_con.Send(client->peer_id, 0, reply, false);
+                               m_con.Send(client->peer_id, 1, reply, false);
                        }
 
                        /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
@@ -1578,16 +1582,16 @@ void Server::AsyncRunStep()
                        // for them.
                        std::list<u16> far_players;
 
-                       if(event->type == MEET_ADDNODE)
+                       if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
                        {
                                //infostream<<"Server: MEET_ADDNODE"<<std::endl;
                                prof.add("MEET_ADDNODE", 1);
                                if(disable_single_change_sending)
                                        sendAddNode(event->p, event->n, event->already_known_by_peer,
-                                                       &far_players, 5);
+                                                       &far_players, 5, event->type == MEET_ADDNODE);
                                else
                                        sendAddNode(event->p, event->n, event->already_known_by_peer,
-                                                       &far_players, 30);
+                                                       &far_players, 30, event->type == MEET_ADDNODE);
                        }
                        else if(event->type == MEET_REMOVENODE)
                        {
@@ -1680,8 +1684,7 @@ void Server::AsyncRunStep()
                {
                        counter = 0.0;
 
-                       for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
-                               m_emerge->emergethread[i]->trigger();
+                       m_emerge->startAllThreads();
 
                        // Update m_enable_rollback_recording here too
                        m_enable_rollback_recording =
@@ -1701,8 +1704,8 @@ void Server::AsyncRunStep()
                        ScopeProfiler sp(g_profiler, "Server: saving stuff");
 
                        //Ban stuff
-                       if(m_banmanager.isModified())
-                               m_banmanager.save();
+                       if(m_banmanager->isModified())
+                               m_banmanager->save();
 
                        // Save changed parts of map
                        m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
@@ -1772,13 +1775,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                addr_s = address.serializeString();
 
                // drop player if is ip is banned
-               if(m_banmanager.isIpBanned(addr_s)){
+               if(m_banmanager->isIpBanned(addr_s)){
+                       std::string ban_name = m_banmanager->getBanName(addr_s);
                        infostream<<"Server: A banned client tried to connect from "
                                        <<addr_s<<"; banned name was "
-                                       <<m_banmanager.getBanName(addr_s)<<std::endl;
+                                       <<ban_name<<std::endl;
                        // This actually doesn't seem to transfer to the client
                        DenyAccess(peer_id, L"Your ip is banned. Banned name was "
-                                       +narrow_to_wide(m_banmanager.getBanName(addr_s)));
+                                       +narrow_to_wide(ban_name));
                        m_con.DeletePeer(peer_id);
                        return;
                }
@@ -1851,7 +1855,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        DenyAccess(peer_id, std::wstring(
                                        L"Your client's version is not supported.\n"
                                        L"Server version is ")
-                                       + narrow_to_wide(VERSION_STRING) + L"."
+                                       + narrow_to_wide(minetest_version_simple) + L"."
                        );
                        return;
                }
@@ -1899,7 +1903,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        DenyAccess(peer_id, std::wstring(
                                        L"Your client's version is not supported.\n"
                                        L"Server version is ")
-                                       + narrow_to_wide(VERSION_STRING) + L",\n"
+                                       + narrow_to_wide(minetest_version_simple) + L",\n"
                                        + L"server's PROTOCOL_VERSION is "
                                        + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
                                        + L"..."
@@ -1921,7 +1925,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                DenyAccess(peer_id, std::wstring(
                                                L"Your client's version is not supported.\n"
                                                L"Server version is ")
-                                               + narrow_to_wide(VERSION_STRING) + L",\n"
+                                               + narrow_to_wide(minetest_version_simple) + L",\n"
                                                + L"server's PROTOCOL_VERSION (strict) is "
                                                + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
                                                + L", client's PROTOCOL_VERSION is "
@@ -1969,6 +1973,19 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        return;
                }
 
+               {
+                       std::string reason;
+                       if(m_script->on_prejoinplayer(playername, addr_s, reason))
+                       {
+                               actionstream<<"Server: Player with the name \""<<playername<<"\" "
+                                               <<"tried to connect from "<<addr_s<<" "
+                                               <<"but it was disallowed for the following reason: "
+                                               <<reason<<std::endl;
+                               DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
+                               return;
+                       }
+               }
+
                infostream<<"Server: New connection: \""<<playername<<"\" from "
                                <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
 
@@ -2159,9 +2176,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                // Send time of day
                {
-                       SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
-                                       m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
-                       m_con.Send(peer_id, 0, data, true);
+                       u16 time = m_env->getTimeOfDay();
+                       float time_speed = g_settings->getFloat("time_speed");
+                       SendTimeOfDay(peer_id, time, time_speed);
                }
 
                // Note things in chat if not in simple singleplayer mode
@@ -2730,7 +2747,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                std::string datastring((char*)&data[2], datasize-2);
                std::istringstream is(datastring, std::ios_base::binary);
 
-               std::list<MediaRequest> tosend;
+               std::list<std::string> tosend;
                u16 numfiles = readU16(is);
 
                infostream<<"Sending "<<numfiles<<" files to "
@@ -2739,7 +2756,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                for(int i = 0; i < numfiles; i++) {
                        std::string name = deSerializeString(is);
-                       tosend.push_back(MediaRequest(name));
+                       tosend.push_back(name);
                        verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
                                        <<name<<std::endl;
                }
@@ -3203,6 +3220,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
        }
 }
 
+void Server::setTimeOfDay(u32 time)
+{
+       m_env->setTimeOfDay(time);
+       m_time_of_day_send_timer = 0;
+}
+
 void Server::onMapEditEvent(MapEditEvent *event)
 {
        //infostream<<"Server::onMapEditEvent()"<<std::endl;
@@ -3293,48 +3316,6 @@ void Server::setInventoryModified(const InventoryLocation &loc)
        }
 }
 
-//std::list<PlayerInfo> Server::getPlayerInfo()
-//{
-//     DSTACK(__FUNCTION_NAME);
-//     JMutexAutoLock envlock(m_env_mutex);
-//     JMutexAutoLock conlock(m_con_mutex);
-//
-//     std::list<PlayerInfo> list;
-//
-//     std::list<Player*> players = m_env->getPlayers();
-//
-//     std::list<Player*>::iterator i;
-//     for(i = players.begin();
-//                     i != players.end(); ++i)
-//     {
-//             PlayerInfo info;
-//
-//             Player *player = *i;
-//
-//             try{
-//                     // Copy info from connection to info struct
-//                     info.id = player->peer_id;
-//                     info.address = m_con.GetPeerAddress(player->peer_id);
-//                     info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
-//             }
-//             catch(con::PeerNotFoundException &e)
-//             {
-//                     // Set dummy peer info
-//                     info.id = 0;
-//                     info.address = Address(0,0,0,0,0);
-//                     info.avg_rtt = 0.0;
-//             }
-//
-//             snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
-//             info.position = player->getPosition();
-//
-//             list.push_back(info);
-//     }
-//
-//     return list;
-//}
-
-
 void Server::peerAdded(con::Peer *peer)
 {
        DSTACK(__FUNCTION_NAME);
@@ -3741,7 +3722,7 @@ void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
        std::string s = os.str();
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
        // Send as reliable
-       m_con.Send(peer_id, 0, data, true);
+       m_con.Send(peer_id, 1, data, true);
 }
 
 void Server::SendHUDRemove(u16 peer_id, u32 id)
@@ -3756,7 +3737,8 @@ void Server::SendHUDRemove(u16 peer_id, u32 id)
        std::string s = os.str();
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
        // Send as reliable
-       m_con.Send(peer_id, 0, data, true);
+
+       m_con.Send(peer_id, 1, data, true);
 }
 
 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
@@ -3841,6 +3823,20 @@ void Server::BroadcastChatMessage(const std::wstring &message)
        }
 }
 
+void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       // Make packet
+       SharedBuffer<u8> data(2+2+4);
+       writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
+       writeU16(&data[2], time);
+       writeF1000(&data[4], time_speed);
+
+       // Send as reliable
+       m_con.Send(peer_id, 0, data, true);
+}
+
 void Server::SendPlayerHP(u16 peer_id)
 {
        DSTACK(__FUNCTION_NAME);
@@ -3848,6 +3844,11 @@ void Server::SendPlayerHP(u16 peer_id)
        assert(playersao);
        playersao->m_hp_not_sent = false;
        SendHP(m_con, peer_id, playersao->getHP());
+
+       // Send to other clients
+       std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
+       ActiveObjectMessage aom(playersao->getId(), true, str);
+       playersao->m_messages_out.push_back(aom);
 }
 
 void Server::SendPlayerBreath(u16 peer_id)
@@ -4083,7 +4084,8 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
 }
 
 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
-               std::list<u16> *far_players, float far_d_nodes)
+               std::list<u16> *far_players, float far_d_nodes,
+               bool remove_metadata)
 {
        float maxd = far_d_nodes*BS;
        v3f p_f = intToFloat(p, BS);
@@ -4119,13 +4121,23 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
                }
 
                // Create packet
-               u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
+               u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
                SharedBuffer<u8> reply(replysize);
                writeU16(&reply[0], TOCLIENT_ADDNODE);
                writeS16(&reply[2], p.X);
                writeS16(&reply[4], p.Y);
                writeS16(&reply[6], p.Z);
                n.serialize(&reply[8], client->serialization_version);
+               u32 index = 8 + MapNode::serializedLength(client->serialization_version);
+               writeU8(&reply[index], remove_metadata ? 0 : 1);
+               
+               if (!remove_metadata) {
+                       if (client->net_proto_version <= 21) {
+                               // Old clients always clear metadata; fix it
+                               // by sending the full block again.
+                               client->SetBlockNotSent(p);
+                       }
+               }
 
                // Send as reliable
                m_con.Send(client->peer_id, 0, reply, true);
@@ -4194,7 +4206,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto
        /*
                Send packet
        */
-       m_con.Send(peer_id, 1, reply, true);
+       m_con.Send(peer_id, 2, reply, true);
 }
 
 void Server::SendBlocks(float dtime)
@@ -4444,7 +4456,7 @@ struct SendableMedia
 };
 
 void Server::sendRequestedMedia(u16 peer_id,
-               const std::list<MediaRequest> &tosend)
+               const std::list<std::string> &tosend)
 {
        DSTACK(__FUNCTION_NAME);
 
@@ -4461,17 +4473,19 @@ void Server::sendRequestedMedia(u16 peer_id,
 
        u32 file_size_bunch_total = 0;
 
-       for(std::list<MediaRequest>::const_iterator i = tosend.begin();
+       for(std::list<std::string>::const_iterator i = tosend.begin();
                        i != tosend.end(); ++i)
        {
-               if(m_media.find(i->name) == m_media.end()){
+               const std::string &name = *i;
+
+               if(m_media.find(name) == m_media.end()){
                        errorstream<<"Server::sendRequestedMedia(): Client asked for "
-                                       <<"unknown file \""<<(i->name)<<"\""<<std::endl;
+                                       <<"unknown file \""<<(name)<<"\""<<std::endl;
                        continue;
                }
 
                //TODO get path + name
-               std::string tpath = m_media[(*i).name].path;
+               std::string tpath = m_media[name].path;
 
                // Read data
                std::ifstream fis(tpath.c_str(), std::ios_base::binary);
@@ -4497,14 +4511,14 @@ void Server::sendRequestedMedia(u16 peer_id,
                }
                if(bad){
                        errorstream<<"Server::sendRequestedMedia(): Failed to read \""
-                                       <<(*i).name<<"\""<<std::endl;
+                                       <<name<<"\""<<std::endl;
                        continue;
                }
                /*infostream<<"Server::sendRequestedMedia(): Loaded \""
                                <<tname<<"\""<<std::endl;*/
                // Put in list
                file_bunches[file_bunches.size()-1].push_back(
-                               SendableMedia((*i).name, tpath, tmp_os.str()));
+                               SendableMedia(name, tpath, tmp_os.str()));
 
                // Start next bunch if got enough data
                if(file_size_bunch_total >= bytes_per_bunch){
@@ -4554,7 +4568,7 @@ void Server::sendRequestedMedia(u16 peer_id,
                                <<" size=" <<s.size()<<std::endl;
                SharedBuffer<u8> data((u8*)s.c_str(), s.size());
                // Send as reliable
-               m_con.Send(peer_id, 0, data, true);
+               m_con.Send(peer_id, 2, data, true);
        }
 }
 
@@ -4658,7 +4672,7 @@ void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
                client->denied = true;
 
        // If there are way too many clients, get rid of denied new ones immediately
-       if(m_clients.size() > 2 * g_settings->getU16("max_users")){
+       if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
                verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
                                <<"peer_id="<<peer_id<<" immediately"<<std::endl;
                // Delete peer to stop sending it data
@@ -4774,9 +4788,6 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
        delete m_clients[peer_id];
        m_clients.erase(peer_id);
 
-       // Send player info to all remaining clients
-       //SendPlayerInfos();
-
        // Send leave chat message to all remaining clients
        if(message.length() != 0)
                BroadcastChatMessage(message);
@@ -4791,7 +4802,10 @@ void Server::UpdateCrafting(u16 peer_id)
 
        // Get a preview for crafting
        ItemStack preview;
+       InventoryLocation loc;
+       loc.setPlayer(player->getName());
        getCraftingResult(&player->inventory, preview, false, this);
+       m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
 
        // Put the new preview in
        InventoryList *plist = player->inventory.getList("craftpreview");
@@ -4818,12 +4832,28 @@ RemoteClient* Server::getClientNoEx(u16 peer_id)
        return n->second;
 }
 
+std::string Server::getPlayerName(u16 peer_id)
+{
+       Player *player = m_env->getPlayer(peer_id);
+       if(player == NULL)
+               return "[id="+itos(peer_id)+"]";
+       return player->getName();
+}
+
+PlayerSAO* Server::getPlayerSAO(u16 peer_id)
+{
+       Player *player = m_env->getPlayer(peer_id);
+       if(player == NULL)
+               return NULL;
+       return player->getPlayerSAO();
+}
+
 std::wstring Server::getStatusString()
 {
        std::wostringstream os(std::ios_base::binary);
        os<<L"# Server: ";
        // Version
-       os<<L"version="<<narrow_to_wide(VERSION_STRING);
+       os<<L"version="<<narrow_to_wide(minetest_version_simple);
        // Uptime
        os<<L", uptime="<<m_uptime.get();
        // Max lag estimate
@@ -4906,11 +4936,19 @@ void Server::reportInventoryFormspecModified(const std::string &name)
        SendPlayerInventoryFormspec(player->peer_id);
 }
 
-// Saves g_settings to configpath given at initialization
-void Server::saveConfig()
+void Server::setIpBanned(const std::string &ip, const std::string &name)
 {
-       if(m_path_config != "")
-               g_settings->updateConfigFile(m_path_config.c_str());
+       m_banmanager->add(ip, name);
+}
+
+void Server::unsetIpBanned(const std::string &ip_or_name)
+{
+       m_banmanager->remove(ip_or_name);
+}
+
+std::string Server::getBanDescription(const std::string &ip_or_name)
+{
+       return m_banmanager->getBanDescription(ip_or_name);
 }
 
 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
@@ -4942,7 +4980,7 @@ u32 Server::hudAdd(Player *player, HudElement *form) {
        if (!player)
                return -1;
 
-       u32 id = hud_get_free_id(player);
+       u32 id = player->getFreeHudID();
        if (id < player->hud.size())
                player->hud[id] = form;
        else
@@ -4991,6 +5029,20 @@ bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
        return true;
 }
 
+void Server::hudSetHotbarImage(Player *player, std::string name) {
+       if (!player)
+               return;
+
+       SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
+}
+
+void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
+       if (!player)
+               return;
+
+       SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
+}
+
 void Server::notifyPlayers(const std::wstring msg)
 {
        BroadcastChatMessage(msg);
@@ -5101,11 +5153,6 @@ void Server::deleteParticleSpawnerAll(u32 id)
        SendDeleteParticleSpawnerAll(id);
 }
 
-void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
-{
-       m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
-}
-
 Inventory* Server::createDetachedInventory(const std::string &name)
 {
        if(m_detached_inventories.count(name) > 0){