]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/network/serverpackethandler.cpp
Clean up ClientReady packet handling
[dragonfireclient.git] / src / network / serverpackethandler.cpp
index 5b378a0832b5c17849e1ec1ab7ef26e21ab6e6f7..8163cb820e54f6d1a7c8816b8cd5d7cc1bf09beb 100644 (file)
@@ -86,7 +86,7 @@ void Server::handleCommand_Init(NetworkPacket* pkt)
 
        // Do not allow multiple players in simple singleplayer mode.
        // This isn't a perfect way to do it, but will suffice for now
-       if (m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1) {
+       if (m_simple_singleplayer_mode && !m_clients.getClientIDs().empty()) {
                infostream << "Server: Not allowing another client (" << addr_s <<
                        ") to connect in simple singleplayer mode" << std::endl;
                DenyAccess(peer_id, SERVER_ACCESSDENIED_SINGLEPLAYER);
@@ -362,16 +362,15 @@ void Server::handleCommand_RequestMedia(NetworkPacket* pkt)
        session_t peer_id = pkt->getPeerId();
        infostream << "Sending " << numfiles << " files to " <<
                getPlayerName(peer_id) << std::endl;
-       verbosestream << "TOSERVER_REQUEST_MEDIA: " << std::endl;
+       verbosestream << "TOSERVER_REQUEST_MEDIA: requested file(s)" << std::endl;
 
        for (u16 i = 0; i < numfiles; i++) {
                std::string name;
 
                *pkt >> name;
 
-               tosend.push_back(name);
-               verbosestream << "TOSERVER_REQUEST_MEDIA: requested file "
-                               << name << std::endl;
+               tosend.emplace_back(name);
+               verbosestream << "  " << name << std::endl;
        }
 
        sendRequestedMedia(peer_id, tosend);
@@ -381,55 +380,47 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
 {
        session_t peer_id = pkt->getPeerId();
 
-       PlayerSAO* playersao = StageTwoClientInit(peer_id);
-
-       if (playersao == NULL) {
-               errorstream << "TOSERVER_CLIENT_READY stage 2 client init failed "
-                       "peer_id=" << peer_id << std::endl;
-               DisconnectPeer(peer_id);
-               return;
-       }
-
-
-       if (pkt->getSize() < 8) {
-               errorstream << "TOSERVER_CLIENT_READY client sent inconsistent data, "
-                       "disconnecting peer_id: " << peer_id << std::endl;
-               DisconnectPeer(peer_id);
-               return;
-       }
-
+       // decode all information first
        u8 major_ver, minor_ver, patch_ver, reserved;
+       u16 formspec_ver = 1; // v1 for clients older than 5.1.0-dev
        std::string full_ver;
+
        *pkt >> major_ver >> minor_ver >> patch_ver >> reserved >> full_ver;
+       if (pkt->getRemainingBytes() >= 2)
+               *pkt >> formspec_ver;
 
        m_clients.setClientVersion(peer_id, major_ver, minor_ver, patch_ver,
                full_ver);
 
-       if (pkt->getRemainingBytes() >= 2)
-               *pkt >> playersao->getPlayer()->formspec_version;
-
-       const std::vector<std::string> &players = m_clients.getPlayerNames();
-       NetworkPacket list_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, peer_id);
-       list_pkt << (u8) PLAYER_LIST_INIT << (u16) players.size();
-       for (const std::string &player: players) {
-               list_pkt <<  player;
+       // Emerge player
+       PlayerSAO* playersao = StageTwoClientInit(peer_id);
+       if (!playersao) {
+               errorstream << "Server: stage 2 client init failed "
+                       "peer_id=" << peer_id << std::endl;
+               DisconnectPeer(peer_id);
+               return;
        }
-       m_clients.send(peer_id, 0, &list_pkt, true);
 
-       NetworkPacket notice_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
-       // (u16) 1 + std::string represents a pseudo vector serialization representation
-       notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(playersao->getPlayer()->getName());
-       m_clients.sendToAll(&notice_pkt);
+       playersao->getPlayer()->formspec_version = formspec_ver;
        m_clients.event(peer_id, CSE_SetClientReady);
 
+       // Send player list to this client
+       {
+               const std::vector<std::string> &players = m_clients.getPlayerNames();
+               NetworkPacket list_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, peer_id);
+               list_pkt << (u8) PLAYER_LIST_INIT << (u16) players.size();
+               for (const auto &player : players)
+                       list_pkt << player;
+               Send(peer_id, &list_pkt);
+       }
+
        s64 last_login;
        m_script->getAuth(playersao->getPlayer()->getName(), nullptr, nullptr, &last_login);
        m_script->on_joinplayer(playersao, last_login);
 
        // Send shutdown timer if shutdown has been scheduled
-       if (m_shutdown_state.isTimerRunning()) {
+       if (m_shutdown_state.isTimerRunning())
                SendChatMessage(peer_id, m_shutdown_state.getShutdownTimerMessage());
-       }
 }
 
 void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
@@ -453,7 +444,7 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
                                ("GOTBLOCKS length is too short");
        }
 
-       m_clients.lock();
+       ClientInterface::AutoLock lock(m_clients);
        RemoteClient *client = m_clients.lockedGetClientNoEx(pkt->getPeerId());
 
        for (u16 i = 0; i < count; i++) {
@@ -461,7 +452,6 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
                *pkt >> p;
                client->GotBlock(p);
        }
-       m_clients.unlock();
 }
 
 void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
@@ -483,7 +473,6 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
        f32 yaw = (f32)f32yaw / 100.0f;
        u32 keyPressed = 0;
 
-       // default behavior (in case an old client doesn't send these)
        f32 fov = 0;
        u8 wanted_range = 0;
 
@@ -509,17 +498,7 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
        playersao->setFov(fov);
        playersao->setWantedRange(wanted_range);
 
-       player->keyPressed = keyPressed;
-       player->control.up    = (keyPressed & (0x1 << 0));
-       player->control.down  = (keyPressed & (0x1 << 1));
-       player->control.left  = (keyPressed & (0x1 << 2));
-       player->control.right = (keyPressed & (0x1 << 3));
-       player->control.jump  = (keyPressed & (0x1 << 4));
-       player->control.aux1  = (keyPressed & (0x1 << 5));
-       player->control.sneak = (keyPressed & (0x1 << 6));
-       player->control.dig   = (keyPressed & (0x1 << 7));
-       player->control.place = (keyPressed & (0x1 << 8));
-       player->control.zoom  = (keyPressed & (0x1 << 9));
+       player->control.unpackKeysPressed(keyPressed);
 
        if (playersao->checkMovementCheat()) {
                // Call callbacks
@@ -831,8 +810,7 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
                                << std::endl;
 
                PlayerHPChangeReason reason(PlayerHPChangeReason::FALL);
-               playersao->setHP((s32)playersao->getHP() - (s32)damage, reason);
-               SendPlayerHPOrDie(playersao, reason);
+               playersao->setHP((s32)playersao->getHP() - (s32)damage, reason, true);
        }
 }
 
@@ -926,6 +904,13 @@ bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std:
        return true;
 }
 
+// Tiny helper to retrieve the selected item into an Optional
+static inline void getWieldedItem(const PlayerSAO *playersao, Optional<ItemStack> &ret)
+{
+       ret = ItemStack();
+       playersao->getWieldedItem(&(*ret));
+}
+
 void Server::handleCommand_Interact(NetworkPacket *pkt)
 {
        /*
@@ -1051,6 +1036,12 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
                if (pointed.type == POINTEDTHING_NODE) {
                        target_pos = intToFloat(pointed.node_undersurface, BS);
                } else if (pointed.type == POINTEDTHING_OBJECT) {
+                       if (playersao->getId() == pointed_object->getId()) {
+                               actionstream << "Server: " << player->getName()
+                                       << " attempted to interact with themselves" << std::endl;
+                               m_script->on_cheat(playersao, "interacted_with_self");
+                               return;
+                       }
                        target_pos = pointed_object->getBasePosition();
                }
                float d = playersao->getEyePosition().getDistanceFrom(target_pos);
@@ -1111,11 +1102,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
                float time_from_last_punch =
                        playersao->resetTimeFromLastPunch();
 
-               u16 src_original_hp = pointed_object->getHP();
-               u16 dst_origin_hp = playersao->getHP();
-
-               u16 wear = pointed_object->punch(dir, &toolcap, playersao,
-                               time_from_last_punch);
+               u32 wear = pointed_object->punch(dir, &toolcap, playersao,
+                               time_from_last_punch, tool_item.wear);
 
                // Callback may have changed item, so get it again
                playersao->getWieldedItem(&selected_item);
@@ -1123,18 +1111,6 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
                if (changed)
                        playersao->setWieldedItem(selected_item);
 
-               // If the object is a player and its HP changed
-               if (src_original_hp != pointed_object->getHP() &&
-                               pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
-                       SendPlayerHPOrDie((PlayerSAO *)pointed_object,
-                                       PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, playersao));
-               }
-
-               // If the puncher is a player and its HP changed
-               if (dst_origin_hp != playersao->getHP())
-                       SendPlayerHPOrDie(playersao,
-                                       PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, pointed_object));
-
                return;
        } // action == INTERACT_START_DIGGING
 
@@ -1180,7 +1156,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
 
                        // Get diggability and expected digging time
                        DigParams params = getDigParams(m_nodedef->get(n).groups,
-                                       &selected_item.getToolCapabilities(m_itemdef));
+                                       &selected_item.getToolCapabilities(m_itemdef),
+                                       selected_item.wear);
                        // If can't dig, try hand
                        if (!params.diggable) {
                                params = getDigParams(m_nodedef->get(n).groups,
@@ -1242,14 +1219,17 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
 
        // Place block or right-click object
        case INTERACT_PLACE: {
-               ItemStack selected_item;
-               playersao->getWieldedItem(&selected_item, nullptr);
+               Optional<ItemStack> selected_item;
+               getWieldedItem(playersao, selected_item);
 
                // Reset build time counter
                if (pointed.type == POINTEDTHING_NODE &&
-                               selected_item.getDefinition(m_itemdef).type == ITEM_NODE)
+                               selected_item->getDefinition(m_itemdef).type == ITEM_NODE)
                        getClient(peer_id)->m_time_from_building = 0.0;
 
+               const bool had_prediction = !selected_item->getDefinition(m_itemdef).
+                       node_placement_prediction.empty();
+
                if (pointed.type == POINTEDTHING_OBJECT) {
                        // Right click object
 
@@ -1262,11 +1242,9 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
                                        << pointed_object->getDescription() << std::endl;
 
                        // Do stuff
-                       if (m_script->item_OnSecondaryUse(
-                                       selected_item, playersao, pointed)) {
-                               if (playersao->setWieldedItem(selected_item)) {
+                       if (m_script->item_OnSecondaryUse(selected_item, playersao, pointed)) {
+                               if (selected_item.has_value() && playersao->setWieldedItem(*selected_item))
                                        SendInventory(playersao, true);
-                               }
                        }
 
                        pointed_object->rightClick(playersao);
@@ -1274,7 +1252,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
                        // Placement was handled in lua
 
                        // Apply returned ItemStack
-                       if (playersao->setWieldedItem(selected_item))
+                       if (selected_item.has_value() && playersao->setWieldedItem(*selected_item))
                                SendInventory(playersao, true);
                }
 
@@ -1286,8 +1264,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
                RemoteClient *client = getClient(peer_id);
                v3s16 blockpos = getNodeBlockPos(pointed.node_abovesurface);
                v3s16 blockpos2 = getNodeBlockPos(pointed.node_undersurface);
-               if (!selected_item.getDefinition(m_itemdef
-                               ).node_placement_prediction.empty()) {
+               if (had_prediction) {
                        client->SetBlockNotSent(blockpos);
                        if (blockpos2 != blockpos)
                                client->SetBlockNotSent(blockpos2);
@@ -1301,15 +1278,15 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
        } // action == INTERACT_PLACE
 
        case INTERACT_USE: {
-               ItemStack selected_item;
-               playersao->getWieldedItem(&selected_item, nullptr);
+               Optional<ItemStack> selected_item;
+               getWieldedItem(playersao, selected_item);
 
-               actionstream << player->getName() << " uses " << selected_item.name
+               actionstream << player->getName() << " uses " << selected_item->name
                                << ", pointing at " << pointed.dump() << std::endl;
 
                if (m_script->item_OnUse(selected_item, playersao, pointed)) {
                        // Apply returned ItemStack
-                       if (playersao->setWieldedItem(selected_item))
+                       if (selected_item.has_value() && playersao->setWieldedItem(*selected_item))
                                SendInventory(playersao, true);
                }
 
@@ -1318,16 +1295,17 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
 
        // Rightclick air
        case INTERACT_ACTIVATE: {
-               ItemStack selected_item;
-               playersao->getWieldedItem(&selected_item, nullptr);
+               Optional<ItemStack> selected_item;
+               getWieldedItem(playersao, selected_item);
 
                actionstream << player->getName() << " activates "
-                               << selected_item.name << std::endl;
+                               << selected_item->name << std::endl;
 
                pointed.type = POINTEDTHING_NOTHING; // can only ever be NOTHING
 
                if (m_script->item_OnSecondaryUse(selected_item, playersao, pointed)) {
-                       if (playersao->setWieldedItem(selected_item))
+                       // Apply returned ItemStack
+                       if (selected_item.has_value() && playersao->setWieldedItem(*selected_item))
                                SendInventory(playersao, true);
                }
 
@@ -1815,3 +1793,30 @@ void Server::handleCommand_ModChannelMsg(NetworkPacket *pkt)
 
        broadcastModChannelMessage(channel_name, channel_msg, peer_id);
 }
+
+void Server::handleCommand_HaveMedia(NetworkPacket *pkt)
+{
+       std::vector<u32> tokens;
+       u8 numtokens;
+
+       *pkt >> numtokens;
+       for (u16 i = 0; i < numtokens; i++) {
+               u32 n;
+               *pkt >> n;
+               tokens.emplace_back(n);
+       }
+
+       const session_t peer_id = pkt->getPeerId();
+       auto player = m_env->getPlayer(peer_id);
+
+       for (const u32 token : tokens) {
+               auto it = m_pending_dyn_media.find(token);
+               if (it == m_pending_dyn_media.end())
+                       continue;
+               if (it->second.waiting_players.count(peer_id)) {
+                       it->second.waiting_players.erase(peer_id);
+                       if (player)
+                               getScriptIface()->on_dynamic_media_added(token, player->getName());
+               }
+       }
+}