Noise: Prevent unittest crash caused by division by zero
[oweals/minetest.git] / src / server.cpp
index 0351fa13b5403147b9473984e6be8e36d26f3dfe..f838ffb556bdfa331bc01ccf6de6bd089f22e07f 100644 (file)
@@ -47,7 +47,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mg_biome.h"
 #include "content_mapnode.h"
 #include "content_nodemeta.h"
-#include "content_abm.h"
 #include "content_sao.h"
 #include "mods.h"
 #include "event_manager.h"
@@ -61,6 +60,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/sha1.h"
 #include "util/hex.h"
 #include "database.h"
+#include "chatmessage.h"
 
 class ClientNotFoundException : public BaseException
 {
@@ -157,41 +157,19 @@ Server::Server(
        m_simple_singleplayer_mode(simple_singleplayer_mode),
        m_dedicated(dedicated),
        m_async_fatal_error(""),
-       m_env(NULL),
        m_con(PROTOCOL_ID,
                        512,
                        CONNECTION_TIMEOUT,
                        ipv6,
                        this),
-       m_banmanager(NULL),
-       m_rollback(NULL),
-       m_enable_rollback_recording(false),
-       m_emerge(NULL),
-       m_script(NULL),
        m_itemdef(createItemDefManager()),
        m_nodedef(createNodeDefManager()),
        m_craftdef(createCraftDefManager()),
        m_event(new EventManager()),
-       m_thread(NULL),
-       m_time_of_day_send_timer(0),
        m_uptime(0),
        m_clients(&m_con),
-       m_shutdown_requested(false),
-       m_shutdown_ask_reconnect(false),
-       m_shutdown_timer(0.0f),
-       m_admin_chat(iface),
-       m_ignore_map_edit_events(false),
-       m_ignore_map_edit_events_peer_id(0),
-       m_next_sound_id(0),
-       m_mod_storage_save_timer(10.0f)
-{
-       m_liquid_transform_timer = 0.0;
-       m_liquid_transform_every = 1.0;
-       m_masterserver_timer = 0.0;
-       m_emergethread_trigger_timer = 0.0;
-       m_savemap_timer = 0.0;
-
-       m_step_dtime = 0.0;
+       m_admin_chat(iface)
+{
        m_lag = g_settings->getFloat("dedicated_server_step");
 
        if(path_world == "")
@@ -318,11 +296,10 @@ Server::Server(
                m_env->loadDefaultMeta();
        }
 
-       // Add some test ActiveBlockModifiers to environment
-       add_legacy_abms(m_env, m_nodedef);
-
        m_liquid_transform_every = g_settings->getFloat("liquid_update");
        m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
+       m_csm_flavour_limits = g_settings->getU64("csm_flavour_limits");
+       m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
 }
 
 Server::~Server()
@@ -330,7 +307,8 @@ Server::~Server()
        infostream<<"Server destructing"<<std::endl;
 
        // Send shutdown message
-       SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
+       SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
+                       L"*** Server shutting down"));
 
        {
                MutexAutoLock envlock(m_env_mutex);
@@ -638,14 +616,15 @@ void Server::AsyncRunStep(bool initial_step)
                ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
 
                // Radius inside which objects are active
-               static const s16 radius =
+               static thread_local const s16 radius =
                        g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
 
                // Radius inside which players are active
-               static const bool is_transfer_limited =
+               static thread_local const bool is_transfer_limited =
                        g_settings->exists("unlimited_player_transfer_distance") &&
                        !g_settings->getBool("unlimited_player_transfer_distance");
-               static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
+               static thread_local const s16 player_transfer_dist =
+                       g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
                s16 player_radius = player_transfer_dist;
                if (player_radius == 0 && is_transfer_limited)
                        player_radius = radius;
@@ -982,7 +961,7 @@ void Server::AsyncRunStep(bool initial_step)
        {
                float &counter = m_savemap_timer;
                counter += dtime;
-               static const float save_interval =
+               static thread_local const float save_interval =
                        g_settings->getFloat("server_map_save_interval");
                if (counter >= save_interval) {
                        counter = 0.0;
@@ -1043,7 +1022,6 @@ void Server::AsyncRunStep(bool initial_step)
 void Server::Receive()
 {
        DSTACK(FUNCTION_NAME);
-       SharedBuffer<u8> data;
        u16 peer_id;
        try {
                NetworkPacket pkt;
@@ -1132,7 +1110,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
        // Note things in chat if not in simple singleplayer mode
        if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
                // Send information about server to player in chat
-               SendChatMessage(peer_id, getStatusString());
+               SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
        }
        Address addr = getPeerAddress(player->peer_id);
        std::string ip_str = addr.serializeString();
@@ -1640,18 +1618,29 @@ void Server::SendInventory(PlayerSAO* playerSAO)
        Send(&pkt);
 }
 
-void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
+void Server::SendChatMessage(u16 peer_id, const ChatMessage &message)
 {
        DSTACK(FUNCTION_NAME);
 
+       NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
+       legacypkt << message.message;
+
        NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
-       pkt << message;
+       u8 version = 1;
+       u8 type = message.type;
+       pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
 
        if (peer_id != PEER_ID_INEXISTENT) {
-               Send(&pkt);
-       }
-       else {
-               m_clients.sendToAll(&pkt);
+               RemotePlayer *player = m_env->getPlayer(peer_id);
+               if (!player)
+                       return;
+
+               if (player->protocol_version < 35)
+                       Send(&legacypkt);
+               else
+                       Send(&pkt);
+       } else {
+               m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
        }
 }
 
@@ -1681,7 +1670,7 @@ void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
                                const struct TileAnimationParams &animation, u8 glow)
 {
        DSTACK(FUNCTION_NAME);
-       static const float radius =
+       static thread_local const float radius =
                        g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
 
        if (peer_id == PEER_ID_INEXISTENT) {
@@ -2029,7 +2018,14 @@ void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, boo
        m_clients.send(pkt.getPeerId(),
                        reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
                        &pkt, reliable);
+}
 
+void Server::SendCSMFlavourLimits(u16 peer_id)
+{
+       NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
+               sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
+       pkt << m_csm_flavour_limits << m_csm_noderange_limit;
+       Send(&pkt);
 }
 
 s32 Server::playSound(const SimpleSoundSpec &spec,
@@ -2095,7 +2091,7 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
        NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
        pkt << id << spec.name << gain
                        << (u8) params.type << pos << params.object
-                       << params.loop << params.fade;
+                       << params.loop << params.fade << params.pitch;
 
        // Backwards compability
        bool play_sound = gain > 0;
@@ -2833,8 +2829,10 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
        }
 
        // Send leave chat message to all remaining clients
-       if(message.length() != 0)
-               SendChatMessage(PEER_ID_INEXISTENT,message);
+       if (!message.empty()) {
+               SendChatMessage(PEER_ID_INEXISTENT,
+                               ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
+       }
 }
 
 void Server::UpdateCrafting(RemotePlayer *player)
@@ -2877,12 +2875,15 @@ void Server::handleChatInterfaceEvent(ChatEvent *evt)
 }
 
 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
-       const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
+       std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
 {
        // If something goes wrong, this player is to blame
        RollbackScopeActor rollback_scope(m_rollback,
                std::string("player:") + name);
 
+       if (g_settings->getBool("strip_color_codes"))
+               wmessage = unescape_enriched(wmessage);
+
        if (player) {
                switch (player->canSendChatMessage()) {
                        case RPLAYER_CHATRESULT_FLOODING: {
@@ -2937,7 +2938,7 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
                /*
                        Send the message to others
                */
-               actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
+               actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
 
                std::vector<u16> clients = m_clients.getClientIDs();
 
@@ -2953,7 +2954,7 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
                for (u16 i = 0; i < clients.size(); i++) {
                        u16 cid = clients[i];
                        if (cid != peer_id_to_avoid_sending)
-                               SendChatMessage(cid, line);
+                               SendChatMessage(cid, ChatMessage(line));
                }
        }
        return L"";
@@ -3115,7 +3116,7 @@ void Server::notifyPlayer(const char *name, const std::wstring &msg)
        if (player->peer_id == PEER_ID_INEXISTENT)
                return;
 
-       SendChatMessage(player->peer_id, msg);
+       SendChatMessage(player->peer_id, ChatMessage(msg));
 }
 
 bool Server::showFormspec(const char *playername, const std::string &formspec,
@@ -3290,7 +3291,7 @@ bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
 
 void Server::notifyPlayers(const std::wstring &msg)
 {
-       SendChatMessage(PEER_ID_INEXISTENT,msg);
+       SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
 }
 
 void Server::spawnParticle(const std::string &playername, v3f pos,
@@ -3517,10 +3518,12 @@ v3f Server::findSpawnPos()
        }
 
        bool is_good = false;
+       // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
+       s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
 
        // Try to find a good place a few times
        for(s32 i = 0; i < 4000 && !is_good; i++) {
-               s32 range = 1 + i;
+               s32 range = MYMIN(1 + i, range_max);
                // We're going to try to throw the player to this position
                v2s16 nodepos2d = v2s16(
                        -range + (myrand() % (range * 2)),
@@ -3668,8 +3671,9 @@ void dedicated_server_loop(Server &server, bool &kill)
 
        IntervalLimiter m_profiler_interval;
 
-       static const float steplen = g_settings->getFloat("dedicated_server_step");
-       static const float profiler_print_interval =
+       static thread_local const float steplen =
+                       g_settings->getFloat("dedicated_server_step");
+       static thread_local const float profiler_print_interval =
                        g_settings->getFloat("profiler_print_interval");
 
        for(;;) {