]> git.lizzy.rs Git - minetest.git/blobdiff - src/server.cpp
Add a setting to enable always flying fast
[minetest.git] / src / server.cpp
index 85e361cede0cbd6f29f83926a7875f0756f6fc18..f635bc676c9a84f2ba4d4dd6229da58c298539c7 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);
@@ -1113,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);
 
@@ -1145,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();
                }
@@ -1373,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);
@@ -1569,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(""));
 
@@ -2039,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;
                        }
@@ -2214,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);
@@ -2244,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
@@ -2258,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);
@@ -2312,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!");
                }
 
                /*
@@ -2379,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);
@@ -2388,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<<")"
@@ -2653,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
                {
@@ -2854,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);
@@ -3188,6 +3222,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        }
 
                } // action == 4
+               
 
                /*
                        Catch invalid actions
@@ -3518,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);
@@ -3530,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());
@@ -3603,6 +3638,25 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
        // Send as reliable
        m_con.Send(peer_id, 0, data, true);
 }
+void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[12];
+
+       // Write command
+       writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
+       os.write((char*)buf, 2);
+       os<<serializeLongString(formspec);
+       os<<serializeString(formname);
+
+       // Make data buffer
+       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);
+}
 
 void Server::BroadcastChatMessage(const std::wstring &message)
 {
@@ -4051,6 +4105,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");
@@ -4076,6 +4131,7 @@ void Server::fillMediaCache()
                                ".png", ".jpg", ".bmp", ".tga",
                                ".pcx", ".ppm", ".psd", ".wal", ".rgb",
                                ".ogg",
+                               ".x", ".b3d", ".md2", ".obj",
                                NULL
                        };
                        if(removeStringEnd(filename, supported_ext) == ""){
@@ -4183,6 +4239,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();
@@ -4190,7 +4247,6 @@ void Server::sendMediaAnnouncement(u16 peer_id)
 
        // Send as reliable
        m_con.Send(peer_id, 0, data, true);
-
 }
 
 struct SendableMedia
@@ -4541,6 +4597,20 @@ void Server::notifyPlayer(const char *name, const std::wstring msg)
        SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
 }
 
+bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
+{
+       Player *player = m_env->getPlayer(playername);
+
+       if(!player)
+       {
+               infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
+               return false;
+       }
+
+       SendShowFormspecMessage(player->peer_id, formspec, formname);
+       return true;
+}
+
 void Server::notifyPlayers(const std::wstring msg)
 {
        BroadcastChatMessage(msg);
@@ -4622,7 +4692,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());
@@ -4654,6 +4724,10 @@ ITextureSource* Server::getTextureSource()
 {
        return NULL;
 }
+IShaderSource* Server::getShaderSource()
+{
+       return NULL;
+}
 u16 Server::allocateUnknownNodeId(const std::string &name)
 {
        return m_nodedef->allocateDummy(name);