]> git.lizzy.rs Git - minetest.git/blobdiff - src/server.cpp
Make m_media_fetch_threads to contain MediaFetchThread* instead of MediaFetchThread
[minetest.git] / src / server.cpp
index a868a0425600bbda00234efce4a0efd76390cd12..39407f961f4d80236f1a1bcb036c070fb6ec96fc 100644 (file)
@@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "constants.h"
 #include "voxel.h"
 #include "config.h"
-#include "servercommand.h"
 #include "filesys.h"
 #include "mapblock.h"
 #include "serverobject.h"
@@ -55,6 +54,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/pointedthing.h"
 #include "util/mathconstants.h"
 #include "rollback.h"
+#include "util/serialize.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -443,9 +443,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
        m_nearest_unsent_reset_timer += dtime;
        
        if(m_nothing_to_send_pause_timer >= 0)
-       {
                return;
-       }
+
+       Player *player = server->m_env->getPlayer(peer_id);
+       // This can happen sometimes; clients and players are not in perfect sync.
+       if(player == NULL)
+               return;
 
        // Won't send anything if already sending
        if(m_blocks_sending.size() >= g_settings->getU16
@@ -457,10 +460,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
 
        //TimeTaker timer("RemoteClient::GetNextBlocks");
        
-       Player *player = server->m_env->getPlayer(peer_id);
-
-       assert(player != NULL);
-
        v3f playerpos = player->getPosition();
        v3f playerspeed = player->getSpeed();
        v3f playerspeeddir(0,0,0);
@@ -937,6 +936,7 @@ Server::Server(
        m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
        m_rollback(NULL),
        m_rollback_sink_enabled(true),
+       m_enable_rollback_recording(false),
        m_lua(NULL),
        m_itemdef(createItemDefManager()),
        m_nodedef(createNodeDefManager()),
@@ -1112,7 +1112,17 @@ Server::~Server()
                        {}
                }
        }
-       
+
+       {
+               JMutexAutoLock envlock(m_env_mutex);
+               JMutexAutoLock conlock(m_con_mutex);
+
+               /*
+                       Execute script shutdown hooks
+               */
+               scriptapi_on_shutdown(m_lua);
+       }
+
        {
                JMutexAutoLock envlock(m_env_mutex);
 
@@ -1144,14 +1154,6 @@ Server::~Server()
                        i = m_clients.getIterator();
                        i.atEnd() == false; i++)
                {
-                       /*// Delete player
-                       // NOTE: These are removed by env destructor
-                       {
-                               u16 peer_id = i.getNode()->getKey();
-                               JMutexAutoLock envlock(m_env_mutex);
-                               m_env->removePlayer(peer_id);
-                       }*/
-                       
                        // Delete client
                        delete i.getNode()->getValue();
                }
@@ -1372,9 +1374,9 @@ void Server::AsyncRunStep()
                        /*
                                Send player inventories and HPs if necessary
                        */
-                       if(playersao->m_teleported){
+                       if(playersao->m_moved){
                                SendMovePlayer(client->peer_id);
-                               playersao->m_teleported = false;
+                               playersao->m_moved = false;
                        }
                        if(playersao->m_inventory_not_sent){
                                UpdateCrafting(client->peer_id);
@@ -1568,7 +1570,7 @@ void Server::AsyncRunStep()
                                
                                if(obj)
                                        data_buffer.append(serializeLongString(
-                                                       obj->getClientInitializationData()));
+                                                       obj->getClientInitializationData(client->net_proto_version)));
                                else
                                        data_buffer.append(serializeLongString(""));
 
@@ -1873,6 +1875,10 @@ void Server::AsyncRunStep()
                        counter = 0.0;
                        
                        m_emergethread.trigger();
+
+                       // Update m_enable_rollback_recording here too
+                       m_enable_rollback_recording =
+                                       g_settings->getBool("enable_rollback_recording");
                }
        }
 
@@ -2034,40 +2040,74 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        Read and check network protocol version
                */
 
-               u16 net_proto_version = 0;
+               u16 min_net_proto_version = 0;
                if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
+                       min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
+
+               // Use same version as minimum and maximum if maximum version field
+               // doesn't exist (backwards compatibility)
+               u16 max_net_proto_version = min_net_proto_version;
+               if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
+                       max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
+
+               // Start with client's maximum version
+               u16 net_proto_version = max_net_proto_version;
+
+               // Figure out a working version if it is possible at all
+               if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
+                               min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
                {
-                       net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
+                       // If maximum is larger than our maximum, go with our maximum
+                       if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
+                               net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
+                       // Else go with client's maximum
+                       else
+                               net_proto_version = max_net_proto_version;
                }
 
+               verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
+                               <<min_net_proto_version<<", max: "<<max_net_proto_version
+                               <<", chosen: "<<net_proto_version<<std::endl;
+
                getClient(peer_id)->net_proto_version = net_proto_version;
 
-               if(net_proto_version == 0)
+               if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
+                               net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
                {
-                       actionstream<<"Server: An old tried to connect from "<<addr_s
+                       actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
                                        <<std::endl;
                        SendAccessDenied(m_con, peer_id, std::wstring(
                                        L"Your client's version is not supported.\n"
                                        L"Server version is ")
-                                       + narrow_to_wide(VERSION_STRING) + L"."
+                                       + narrow_to_wide(VERSION_STRING) + L",\n"
+                                       + L"server's PROTOCOL_VERSION is "
+                                       + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
+                                       + L"..."
+                                       + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
+                                       + L", client's PROTOCOL_VERSION is "
+                                       + narrow_to_wide(itos(min_net_proto_version))
+                                       + L"..."
+                                       + narrow_to_wide(itos(max_net_proto_version))
                        );
                        return;
                }
                
                if(g_settings->getBool("strict_protocol_version_checking"))
                {
-                       if(net_proto_version != PROTOCOL_VERSION)
+                       if(net_proto_version != LATEST_PROTOCOL_VERSION)
                        {
-                               actionstream<<"Server: A mismatched client tried to connect"
-                                               <<" from "<<addr_s<<std::endl;
+                               actionstream<<"Server: A mismatched (strict) client tried to "
+                                               <<"connect from "<<addr_s<<std::endl;
                                SendAccessDenied(m_con, peer_id, std::wstring(
                                                L"Your client's version is not supported.\n"
                                                L"Server version is ")
                                                + narrow_to_wide(VERSION_STRING) + L",\n"
-                                               + L"server's PROTOCOL_VERSION is "
-                                               + narrow_to_wide(itos(PROTOCOL_VERSION))
+                                               + L"server's PROTOCOL_VERSION (strict) is "
+                                               + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
                                                + L", client's PROTOCOL_VERSION is "
-                                               + narrow_to_wide(itos(net_proto_version))
+                                               + narrow_to_wide(itos(min_net_proto_version))
+                                               + L"..."
+                                               + narrow_to_wide(itos(max_net_proto_version))
                                );
                                return;
                        }
@@ -2209,11 +2249,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        Answer with a TOCLIENT_INIT
                */
                {
-                       SharedBuffer<u8> reply(2+1+6+8);
+                       SharedBuffer<u8> reply(2+1+6+8+4);
                        writeU16(&reply[0], TOCLIENT_INIT);
                        writeU8(&reply[2], deployed);
                        writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
                        writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
+                       writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
                        
                        // Send as reliable
                        m_con.Send(peer_id, 0, reply, true);
@@ -2239,8 +2280,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        return;
                }
 
-               getClient(peer_id)->serialization_version
-                               = getClient(peer_id)->pending_serialization_version;
+               RemoteClient *client = getClient(peer_id);
+               client->serialization_version =
+                               getClient(peer_id)->pending_serialization_version;
 
                /*
                        Send some initialization data
@@ -2253,7 +2295,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                SendItemDef(m_con, peer_id, m_itemdef);
                
                // Send node definitions
-               SendNodeDef(m_con, peer_id, m_nodedef);
+               SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
                
                // Send media announcement
                sendMediaAnnouncement(peer_id);
@@ -2307,9 +2349,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                }
                
                // Warnings about protocol version can be issued here
-               if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
+               if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
                {
-                       SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
+                       SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
+                                       L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
                }
 
                /*
@@ -2374,6 +2417,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                v3s32 ss = readV3S32(&data[start+2+12]);
                f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
                f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
+               u32 keyPressed = 0;
+               if(datasize >= 2+12+12+4+4+4)
+                       keyPressed = (u32)readU32(&data[2+12+12+4+4]);
                v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
                v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
                pitch = wrapDegrees(pitch);
@@ -2383,6 +2429,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                player->setSpeed(speed);
                player->setPitch(pitch);
                player->setYaw(yaw);
+               player->keyPressed=keyPressed;
+               player->control.up = (bool)(keyPressed&1);
+               player->control.down = (bool)(keyPressed&2);
+               player->control.left = (bool)(keyPressed&4);
+               player->control.right = (bool)(keyPressed&8);
+               player->control.jump = (bool)(keyPressed&16);
+               player->control.aux1 = (bool)(keyPressed&32);
+               player->control.sneak = (bool)(keyPressed&64);
+               player->control.LMB = (bool)(keyPressed&128);
+               player->control.RMB = (bool)(keyPressed&256);
                
                /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
                                <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
@@ -2627,6 +2683,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        message += (wchar_t)readU16(buf);
                }
 
+               // If something goes wrong, this player is to blame
+               RollbackScopeActor rollback_scope(m_rollback,
+                               std::string("player:")+player->getName());
+
                // Get player name of this client
                std::wstring name = narrow_to_wide(player->getName());
                
@@ -2644,36 +2704,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // Whether to send to other players
                bool send_to_others = false;
                
-               // Parse commands
+               // Commands are implemented in Lua, so only catch invalid
+               // commands that were not "eaten" and send an error back
                if(message[0] == L'/')
                {
-                       size_t strip_size = 1;
-                       if (message[1] == L'#') // support old-style commans
-                               ++strip_size;
-                       message = message.substr(strip_size);
-
-                       WStrfnd f1(message);
-                       f1.next(L" "); // Skip over /#whatever
-                       std::wstring paramstring = f1.next(L"");
-
-                       ServerCommandContext *ctx = new ServerCommandContext(
-                               str_split(message, L' '),
-                               paramstring,
-                               this,
-                               m_env,
-                               player);
-
-                       std::wstring reply(processServerCommand(ctx));
-                       send_to_sender = ctx->flags & SEND_TO_SENDER;
-                       send_to_others = ctx->flags & SEND_TO_OTHERS;
-
-                       if (ctx->flags & SEND_NO_PREFIX)
-                               line += reply;
+                       message = message.substr(1);
+                       send_to_sender = true;
+                       if(message.length() == 0)
+                               line += L"-!- Empty command";
                        else
-                               line += L"Server: " + reply;
-
-                       delete ctx;
-
+                               line += L"-!- Invalid command: " + str_split(message, L' ')[0];
                }
                else
                {
@@ -2845,6 +2885,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // (definitions and files)
                getClient(peer_id)->definitions_sent = true;
        }
+       else if(command == TOSERVER_RECEIVED_MEDIA) {
+               getClient(peer_id)->definitions_sent = true;
+       }
        else if(command == TOSERVER_INTERACT)
        {
                std::string datastring((char*)&data[2], datasize-2);
@@ -3179,6 +3222,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        }
 
                } // action == 4
+               
 
                /*
                        Catch invalid actions
@@ -3509,7 +3553,7 @@ void Server::SendItemDef(con::Connection &con, u16 peer_id,
 }
 
 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
-               INodeDefManager *nodedef)
+               INodeDefManager *nodedef, u16 protocol_version)
 {
        DSTACK(__FUNCTION_NAME);
        std::ostringstream os(std::ios_base::binary);
@@ -3521,7 +3565,7 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
        */
        writeU16(os, TOCLIENT_NODEDEF);
        std::ostringstream tmp_os(std::ios::binary);
-       nodedef->serialize(tmp_os);
+       nodedef->serialize(tmp_os, protocol_version);
        std::ostringstream tmp_os2(std::ios::binary);
        compressZlib(tmp_os.str(), tmp_os2);
        os<<serializeLongString(tmp_os2.str());
@@ -4042,6 +4086,7 @@ void Server::fillMediaCache()
                paths.push_back(mod.path + DIR_DELIM + "textures");
                paths.push_back(mod.path + DIR_DELIM + "sounds");
                paths.push_back(mod.path + DIR_DELIM + "media");
+               paths.push_back(mod.path + DIR_DELIM + "models");
        }
        std::string path_all = "textures";
        paths.push_back(path_all + DIR_DELIM + "all");
@@ -4067,6 +4112,7 @@ void Server::fillMediaCache()
                                ".png", ".jpg", ".bmp", ".tga",
                                ".pcx", ".ppm", ".psd", ".wal", ".rgb",
                                ".ogg",
+                               ".x", ".b3d", ".md2", ".obj",
                                NULL
                        };
                        if(removeStringEnd(filename, supported_ext) == ""){
@@ -4174,6 +4220,7 @@ void Server::sendMediaAnnouncement(u16 peer_id)
                os<<serializeString(j->name);
                os<<serializeString(j->sha1_digest);
        }
+       os<<serializeString(g_settings->get("remote_media"));
 
        // Make data buffer
        std::string s = os.str();
@@ -4181,7 +4228,6 @@ void Server::sendMediaAnnouncement(u16 peer_id)
 
        // Send as reliable
        m_con.Send(peer_id, 0, data, true);
-
 }
 
 struct SendableMedia
@@ -4440,9 +4486,10 @@ std::wstring Server::getStatusString()
        // Uptime
        os<<L", uptime="<<m_uptime.get();
        // Information about clients
+       core::map<u16, RemoteClient*>::Iterator i;
+       bool first;
        os<<L", clients={";
-       for(core::map<u16, RemoteClient*>::Iterator
-               i = m_clients.getIterator();
+       for(i = m_clients.getIterator(), first = true;
                i.atEnd() == false; i++)
        {
                // Get client and check that it is valid
@@ -4457,7 +4504,11 @@ std::wstring Server::getStatusString()
                if(player != NULL)
                        name = narrow_to_wide(player->getName());
                // Add name to information string
-               os<<name<<L",";
+               if(!first)
+                       os<<L",";
+               else
+                       first = false;
+               os<<name;
        }
        os<<L"}";
        if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
@@ -4608,7 +4659,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
                                log->push_back(os.str());
                }else{
                        std::ostringstream os;
-                       os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
+                       os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
                        infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
                        if(log)
                                log->push_back(os.str());
@@ -4640,6 +4691,10 @@ ITextureSource* Server::getTextureSource()
 {
        return NULL;
 }
+IShaderSource* Server::getShaderSource()
+{
+       return NULL;
+}
 u16 Server::allocateUnknownNodeId(const std::string &name)
 {
        return m_nodedef->allocateDummy(name);
@@ -4654,6 +4709,8 @@ MtEventManager* Server::getEventManager()
 }
 IRollbackReportSink* Server::getRollbackReportSink()
 {
+       if(!m_enable_rollback_recording)
+               return NULL;
        if(!m_rollback_sink_enabled)
                return NULL;
        return m_rollback;