]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/server.cpp
Fix doc and forceloading crash.
[dragonfireclient.git] / src / server.cpp
index 4df2162a7d00c31fd2ecc07586077de0df9786e7..b257448a1c4e2de8b1b7091ffd74e103352e4c2a 100644 (file)
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "constants.h"
 #include "voxel.h"
 #include "config.h"
+#include "version.h"
 #include "filesys.h"
 #include "mapblock.h"
 #include "serverobject.h"
@@ -72,14 +73,14 @@ class ClientNotFoundException : public BaseException
        {}
 };
 
-class ServerThread : public SimpleThread
+class ServerThread : public JThread
 {
        Server *m_server;
 
 public:
 
        ServerThread(Server *server):
-               SimpleThread(),
+               JThread(),
                m_server(server)
        {
        }
@@ -89,15 +90,16 @@ class ServerThread : public SimpleThread
 
 void * ServerThread::Thread()
 {
-       ThreadStarted();
-
        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()");
@@ -672,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");
@@ -706,6 +705,10 @@ Server::Server(
        // Create emerge manager
        m_emerge = new EmergeManager(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);
@@ -714,15 +717,11 @@ Server::Server(
        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");
-
        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)
@@ -741,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));
        }
@@ -756,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)
@@ -826,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);
@@ -965,14 +965,13 @@ 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();
 
        // ASCII art for the win!
@@ -995,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;
@@ -1020,7 +1019,7 @@ void Server::step(float dtime)
        }
 }
 
-void Server::AsyncRunStep()
+void Server::AsyncRunStep(bool initial_step)
 {
        DSTACK(__FUNCTION_NAME);
 
@@ -1037,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);
@@ -1243,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
@@ -1257,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;
@@ -1529,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)
@@ -1582,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)
                        {
@@ -1684,7 +1684,7 @@ void Server::AsyncRunStep()
                {
                        counter = 0.0;
 
-                       m_emerge->triggerAllThreads();
+                       m_emerge->startAllThreads();
 
                        // Update m_enable_rollback_recording here too
                        m_enable_rollback_recording =
@@ -1855,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;
                }
@@ -1903,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"..."
@@ -1925,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 "
@@ -1973,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;
 
@@ -2734,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 "
@@ -2743,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;
                }
@@ -3709,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)
@@ -3724,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)
@@ -4070,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);
@@ -4106,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);
@@ -4181,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)
@@ -4431,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);
 
@@ -4448,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);
@@ -4484,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){
@@ -4541,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);
        }
 }
 
@@ -4645,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
@@ -4775,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");
@@ -4823,7 +4853,7 @@ 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