]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/network/clientpackethandler.cpp
Chat protocol rewrite (#5117)
[dragonfireclient.git] / src / network / clientpackethandler.cpp
index dfaebbe533e12226ebd94f3f9c43eb916f4b5e01..bb4db6f47b26ab607df539a7aabde0f647f93033 100644 (file)
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "client.h"
 
 #include "util/base64.h"
+#include "chatmessage.h"
 #include "clientmedia.h"
 #include "log.h"
 #include "map.h"
@@ -30,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "server.h"
 #include "util/strfnd.h"
 #include "network/clientopcodes.h"
-#include "script/clientscripting.h"
+#include "script/scripting_client.h"
 #include "util/serialize.h"
 #include "util/srp.h"
 #include "tileanimation.h"
@@ -142,7 +143,9 @@ void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
 }
 void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
 {
-       pushToChatQueue(L"Password change denied. Password NOT changed.");
+       ChatMessage *chatMessage = new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
+                       L"Password change denied. Password NOT changed.");
+       pushToChatQueue(chatMessage);
        // reset everything and be sad
        deleteAuthData();
 }
@@ -395,7 +398,7 @@ void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
                        << " dr=" << dr << std::endl;
 }
 
-void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
+void Client::handleCommand_ChatMessageOld(NetworkPacket *pkt)
 {
        /*
                u16 command
@@ -413,8 +416,43 @@ void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
        }
 
        // If chat message not consummed by client lua API
+       // @TODO send this to CSM using ChatMessage object
        if (!moddingEnabled() || !m_script->on_receiving_message(wide_to_utf8(message))) {
-               pushToChatQueue(message);
+               pushToChatQueue(new ChatMessage(message));
+       }
+}
+
+void Client::handleCommand_ChatMessage(NetworkPacket *pkt)
+{
+       /*
+               u8 version
+               u8 message_type
+               u16 sendername length
+               wstring sendername
+               u16 length
+               wstring message
+        */
+
+       ChatMessage *chatMessage = new ChatMessage();
+       u8 version, message_type;
+       *pkt >> version >> message_type;
+
+       if (version != 1 || message_type >= CHATMESSAGE_TYPE_MAX) {
+               delete chatMessage;
+               return;
+       }
+
+       *pkt >> chatMessage->sender >> chatMessage->message >> chatMessage->timestamp;
+
+       chatMessage->type = (ChatMessageType) message_type;
+
+       // @TODO send this to CSM using ChatMessage object
+       if (!moddingEnabled() || !m_script->on_receiving_message(
+                       wide_to_utf8(chatMessage->message))) {
+               pushToChatQueue(chatMessage);
+       } else {
+               // Message was consumed by CSM and should not handled by client, destroying
+               delete chatMessage;
        }
 }
 
@@ -561,7 +599,6 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
 
        *pkt >> pos >> pitch >> yaw;
 
-       player->got_teleported = true;
        player->setPosition(pos);
 
        infostream << "Client got TOCLIENT_MOVE_PLAYER"
@@ -587,11 +624,6 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
        m_ignore_damage_timer = 3.0;
 }
 
-void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
-{
-       warningstream << "Client: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
-}
-
 void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
 {
        bool set_camera_point_target;
@@ -689,8 +721,7 @@ void Client::handleCommand_Media(NetworkPacket* pkt)
        if (num_files == 0)
                return;
 
-       if (m_media_downloader == NULL ||
-                       !m_media_downloader->isStarted()) {
+       if (!m_media_downloader || !m_media_downloader->isStarted()) {
                const char *problem = m_media_downloader ?
                        "media has not been requested" :
                        "all media has been received already";
@@ -718,11 +749,6 @@ void Client::handleCommand_Media(NetworkPacket* pkt)
        }
 }
 
-void Client::handleCommand_ToolDef(NetworkPacket* pkt)
-{
-       warningstream << "Client: Ignoring TOCLIENT_TOOLDEF" << std::endl;
-}
-
 void Client::handleCommand_NodeDef(NetworkPacket* pkt)
 {
        infostream << "Client: Received node definitions: packet size: "
@@ -733,9 +759,7 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
        sanity_check(!m_mesh_update_thread.isRunning());
 
        // Decompress node definitions
-       std::string datastring(pkt->getString(0), pkt->getSize());
-       std::istringstream is(datastring, std::ios_base::binary);
-       std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+       std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
        std::ostringstream tmp_os;
        decompressZlib(tmp_is, tmp_os);
 
@@ -745,11 +769,6 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
        m_nodedef_received = true;
 }
 
-void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
-{
-       warningstream << "Client: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
-}
-
 void Client::handleCommand_ItemDef(NetworkPacket* pkt)
 {
        infostream << "Client: Received item definitions: packet size: "
@@ -760,9 +779,7 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
        sanity_check(!m_mesh_update_thread.isRunning());
 
        // Decompress item definitions
-       std::string datastring(pkt->getString(0), pkt->getSize());
-       std::istringstream is(datastring, std::ios_base::binary);
-       std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+       std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
        std::ostringstream tmp_os;
        decompressZlib(tmp_is, tmp_os);
 
@@ -774,31 +791,52 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
 
 void Client::handleCommand_PlaySound(NetworkPacket* pkt)
 {
+       /*
+               [0] u32 server_id
+               [4] u16 name length
+               [6] char name[len]
+               [ 6 + len] f32 gain
+               [10 + len] u8 type
+               [11 + len] (f32 * 3) pos
+               [23 + len] u16 object_id
+               [25 + len] bool loop
+               [26 + len] f32 fade
+               [30 + len] f32 pitch
+       */
+
        s32 server_id;
        std::string name;
+
        float gain;
        u8 type; // 0=local, 1=positional, 2=object
        v3f pos;
        u16 object_id;
        bool loop;
+       float fade = 0.0f;
+       float pitch = 1.0f;
 
        *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
 
+       try {
+               *pkt >> fade;
+               *pkt >> pitch;
+       } catch (PacketError &e) {};
+
        // Start playing
        int client_id = -1;
        switch(type) {
                case 0: // local
-                       client_id = m_sound->playSound(name, loop, gain);
+                       client_id = m_sound->playSound(name, loop, gain, fade, pitch);
                        break;
                case 1: // positional
-                       client_id = m_sound->playSoundAt(name, loop, gain, pos);
+                       client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
                        break;
                case 2:
                { // object
                        ClientActiveObject *cao = m_env.getActiveObject(object_id);
                        if (cao)
                                pos = cao->getPosition();
-                       client_id = m_sound->playSoundAt(name, loop, gain, pos);
+                       client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch);
                        // TODO: Set up sound to move with object
                        break;
                }
@@ -820,13 +858,28 @@ void Client::handleCommand_StopSound(NetworkPacket* pkt)
 
        *pkt >> server_id;
 
-       UNORDERED_MAP<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
+       std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
        if (i != m_sounds_server_to_client.end()) {
                int client_id = i->second;
                m_sound->stopSound(client_id);
        }
 }
 
+void Client::handleCommand_FadeSound(NetworkPacket *pkt)
+{
+       s32 sound_id;
+       float step;
+       float gain;
+
+       *pkt >> sound_id >> step >> gain;
+
+       std::unordered_map<s32, int>::const_iterator i =
+                       m_sounds_server_to_client.find(sound_id);
+
+       if (i != m_sounds_server_to_client.end())
+               m_sound->fadeSound(i->second, step, gain);
+}
+
 void Client::handleCommand_Privileges(NetworkPacket* pkt)
 {
        m_privileges.clear();
@@ -1137,7 +1190,7 @@ void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
        m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
 
        // Hide minimap if it has been disabled by the server
-       if (m_minimap_disabled_by_server && was_minimap_visible) {
+       if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible) {
                // defers a minimap update, therefore only call it if really
                // needed, by checking that minimap was visible before
                m_minimap->setMinimapMode(MINIMAP_MODE_OFF);
@@ -1159,9 +1212,21 @@ void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
                        player->hud_hotbar_itemcount = hotbar_itemcount;
        }
        else if (param == HUD_PARAM_HOTBAR_IMAGE) {
+               // If value not empty verify image exists in texture source
+               if (value != "" && !getTextureSource()->isKnownSourceImage(value)) {
+                       errorstream << "Server sent wrong Hud hotbar image (sent value: '"
+                               << value << "')" << std::endl;
+                       return;
+               }
                player->hotbar_image = value;
        }
        else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
+               // If value not empty verify image exists in texture source
+               if (value != "" && !getTextureSource()->isKnownSourceImage(value)) {
+                       errorstream << "Server sent wrong Hud hotbar selected image (sent value: '"
+                                       << value << "')" << std::endl;
+                       return;
+               }
                player->hotbar_selected_image = value;
        }
 }
@@ -1179,11 +1244,45 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
        for (size_t i = 0; i < count; i++)
                params->push_back(deSerializeString(is));
 
+       bool clouds = true;
+       try {
+               clouds = readU8(is);
+       } catch (...) {}
+
        ClientEvent event;
        event.type            = CE_SET_SKY;
        event.set_sky.bgcolor = bgcolor;
        event.set_sky.type    = type;
        event.set_sky.params  = params;
+       event.set_sky.clouds  = clouds;
+       m_client_event_queue.push(event);
+}
+
+void Client::handleCommand_CloudParams(NetworkPacket* pkt)
+{
+       f32 density;
+       video::SColor color_bright;
+       video::SColor color_ambient;
+       f32 height;
+       f32 thickness;
+       v2f speed;
+
+       *pkt >> density >> color_bright >> color_ambient
+                       >> height >> thickness >> speed;
+
+       ClientEvent event;
+       event.type                       = CE_CLOUD_PARAMS;
+       event.cloud_params.density       = density;
+       // use the underlying u32 representation, because we can't
+       // use struct members with constructors here, and this way
+       // we avoid using new() and delete() for no good reason
+       event.cloud_params.color_bright  = color_bright.color;
+       event.cloud_params.color_ambient = color_ambient.color;
+       event.cloud_params.height        = height;
+       event.cloud_params.thickness     = thickness;
+       // same here: deconstruct to skip constructor
+       event.cloud_params.speed_x       = speed.X;
+       event.cloud_params.speed_y       = speed.Y;
        m_client_event_queue.push(event);
 }
 
@@ -1223,6 +1322,28 @@ void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
        *pkt >> player->eye_offset_first >> player->eye_offset_third;
 }
 
+void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt)
+{
+       u8 type;
+       u16 num_players;
+       *pkt >> type >> num_players;
+       PlayerListModifer notice_type = (PlayerListModifer) type;
+
+       for (u16 i = 0; i < num_players; i++) {
+               std::string name;
+               *pkt >> name;
+               switch (notice_type) {
+               case PLAYER_LIST_INIT:
+               case PLAYER_LIST_ADD:
+                       m_env.addPlayerName(name);
+                       continue;
+               case PLAYER_LIST_REMOVE:
+                       m_env.removePlayerName(name);
+                       continue;
+               }
+       }
+}
+
 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
 {
        if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)