diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index 80014cdec..208630358 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -20,6 +20,7 @@ #include "config/player_manager.hpp" #include "karts/kart_properties_manager.hpp" +#include "guiengine/modaldialog.hpp" #include "guiengine/message_queue.hpp" #include "modes/world_with_rank.hpp" #include "network/event.hpp" @@ -369,6 +370,8 @@ void ClientLobby::update(float dt) break; case KART_SELECTION: { + // In case the user opened a user info dialog + GUIEngine::ModalDialog::dismiss(); NetworkKartSelectionScreen* screen = NetworkKartSelectionScreen::getInstance(); screen->setAvailableKartsFromServer(m_available_karts); diff --git a/src/network/protocols/lobby_protocol.hpp b/src/network/protocols/lobby_protocol.hpp index 56e701299..ec75ac45d 100644 --- a/src/network/protocols/lobby_protocol.hpp +++ b/src/network/protocols/lobby_protocol.hpp @@ -62,7 +62,8 @@ public: LE_VOTE_LAPS, // vote number of laps LE_CHAT, LE_FINAL_PLAYER_LIST, - LE_AUTHORISED + LE_AUTHORISED, + LE_KICK_HOST }; enum RejectReason : uint8_t diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b4d4947ee..b5a0149aa 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -160,7 +160,20 @@ bool ServerLobby::notifyEvent(Event* event) } // notifyEvent //----------------------------------------------------------------------------- +void ServerLobby::kickHost(Event* event) +{ + std::unique_lock lock(m_connection_mutex); + if (m_server_owner.lock() != event->getPeerSP()) + return; + lock.unlock(); + NetworkString& data = event->data(); + uint32_t host_id = data.getUInt32(); + std::shared_ptr peer = STKHost::get()->findPeerByHostId(host_id); + if (peer) + peer->kick(); +} // kickHost +//----------------------------------------------------------------------------- bool ServerLobby::notifyEventAsynchronous(Event* event) { assert(m_game_setup); // assert that the setup exists @@ -185,6 +198,8 @@ bool ServerLobby::notifyEventAsynchronous(Event* event) case LE_VOTE_REVERSE: playerReversedVote(event); break; case LE_VOTE_LAPS: playerLapsVote(event); break; case LE_RACE_FINISHED_ACK: playerFinishedResult(event); break; + case LE_KICK_HOST: kickHost(event); break; + default: break; } // switch } // if (event->getType() == EVENT_TYPE_MESSAGE) else if (event->getType() == EVENT_TYPE_DISCONNECTED) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 40ec450e2..87b78cd72 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -95,6 +95,7 @@ private: void registerServer(); void finishedLoadingWorldClient(Event *event); void startedRaceOnClient(Event *event); + void kickHost(Event* event); void unregisterServer(); void createServerIdFile(); void updatePlayerList(); diff --git a/src/states_screens/dialogs/network_user_dialog.cpp b/src/states_screens/dialogs/network_user_dialog.cpp new file mode 100644 index 000000000..2ccb247b3 --- /dev/null +++ b/src/states_screens/dialogs/network_user_dialog.cpp @@ -0,0 +1,99 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "states_screens/dialogs/network_user_dialog.hpp" + +#include "config/player_manager.hpp" +#include "guiengine/dialog_queue.hpp" +#include "guiengine/engine.hpp" +#include "online/online_profile.hpp" +#include "network/protocols/lobby_protocol.hpp" +#include "network/stk_host.hpp" +#include "states_screens/state_manager.hpp" +#include "utils/translation.hpp" + +#include + +using namespace GUIEngine; +using namespace irr; +using namespace irr::gui; +using namespace Online; + +// ---------------------------------------------------------------------------- +void NetworkUserDialog::beforeAddingWidgets() +{ + m_options_widget = getWidget("options"); + assert(m_options_widget != NULL); + m_name_widget = getWidget("name"); + assert(m_name_widget != NULL); + m_name_widget->setText(m_name, false); + + m_options_widget = getWidget("options"); + assert(m_options_widget != NULL); + + m_friend_widget = getWidget("friend"); + assert(m_friend_widget != NULL); + m_kick_widget = getWidget("decline"); + assert(m_kick_widget != NULL); + + //I18N: In the network user dialog + m_kick_widget->setText(_("Kick")); + m_kick_widget->setVisible(STKHost::get()->isAuthorisedToControl()); + + m_cancel_widget = getWidget("cancel"); + assert(m_cancel_widget != NULL); + m_cancel_widget->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + + getWidget("accept")->setVisible(false); + getWidget("remove")->setVisible(false); + getWidget("enter")->setVisible(false); + getWidget("info")->setVisible(false); +} // beforeAddingWidgets + +// ----------------------------------------------------------------------------- +GUIEngine::EventPropagation + NetworkUserDialog::processEvent(const std::string& source) +{ + if (source == m_options_widget->m_properties[PROP_ID]) + { + const std::string& selection = m_options_widget + ->getSelectionIDString(PLAYER_ID_GAME_MASTER); + if (selection == m_cancel_widget->m_properties[PROP_ID]) + { + m_self_destroy = true; + return GUIEngine::EVENT_BLOCK; + } + else if(selection == m_friend_widget->m_properties[PROP_ID]) + { + XMLRequest *request = new XMLRequest(); + PlayerManager::setUserDetails(request, "friend-request"); + request->addParameter("friendid", m_online_id); + request->queue(); + m_self_destroy = true; + return GUIEngine::EVENT_BLOCK; + } + else if(selection == m_kick_widget->m_properties[PROP_ID]) + { + NetworkString kick(PROTOCOL_LOBBY_ROOM); + kick.addUInt8(LobbyProtocol::LE_KICK_HOST).addUInt32(m_host_id); + STKHost::get()->sendToServer(&kick, true/*reliable*/); + m_self_destroy = true; + return GUIEngine::EVENT_BLOCK; + } + } + return GUIEngine::EVENT_LET; +} // processEvent diff --git a/src/states_screens/dialogs/network_user_dialog.hpp b/src/states_screens/dialogs/network_user_dialog.hpp new file mode 100644 index 000000000..ad2208046 --- /dev/null +++ b/src/states_screens/dialogs/network_user_dialog.hpp @@ -0,0 +1,93 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef HEADER_USER_INFO_DIALOG_HPP +#define HEADER_USER_INFO_DIALOG_HPP + +#include "guiengine/modaldialog.hpp" +#include "guiengine/widgets.hpp" +#include "utils/types.hpp" + +#include + +namespace Online +{ + class OnlineProfile; +} + +/** + * \brief Dialog that handle user in network lobby + * \ingroup states_screens + */ +class NetworkUserDialog : public GUIEngine::ModalDialog +{ +private: + const uint32_t m_host_id; + + const uint32_t m_online_id; + + const core::stringw m_name; + + bool m_self_destroy; + + GUIEngine::RibbonWidget * m_options_widget; + + GUIEngine::LabelWidget * m_name_widget; + + GUIEngine::IconButtonWidget * m_friend_widget; + + GUIEngine::IconButtonWidget * m_kick_widget; + + GUIEngine::IconButtonWidget * m_cancel_widget; + +public: + NetworkUserDialog(uint32_t host_id, uint32_t online_id, + const core::stringw& name) + : ModalDialog(0.8f,0.8f), m_host_id(host_id), m_online_id(online_id), + m_name(name), m_self_destroy(false) + { + loadFromFile("online/user_info_dialog.stkgui"); + } + // ------------------------------------------------------------------------ + ~NetworkUserDialog() {} + // ------------------------------------------------------------------------ + virtual void beforeAddingWidgets(); + // ------------------------------------------------------------------------ + void onEnterPressedInternal() { m_self_destroy = true; } + // ------------------------------------------------------------------------ + GUIEngine::EventPropagation processEvent(const std::string& source); + // ------------------------------------------------------------------------ + virtual bool onEscapePressed() + { + if (m_cancel_widget->isActivated()) + m_self_destroy = true; + return false; + } + // ------------------------------------------------------------------------ + virtual void onUpdate(float dt) + { + // It's unsafe to delete from inside the event handler so we do it here + if (m_self_destroy) + { + ModalDialog::dismiss(); + return; + } + } +}; + +#endif diff --git a/src/states_screens/networking_lobby.cpp b/src/states_screens/networking_lobby.cpp index 058d12e71..92504380a 100644 --- a/src/states_screens/networking_lobby.cpp +++ b/src/states_screens/networking_lobby.cpp @@ -39,7 +39,7 @@ #include "network/server.hpp" #include "network/stk_host.hpp" #include "states_screens/state_manager.hpp" -#include "states_screens/dialogs/message_dialog.hpp" +#include "states_screens/dialogs/network_user_dialog.hpp" #include "utils/translation.hpp" using namespace Online; @@ -101,7 +101,6 @@ void NetworkingLobby::beforeAddingWidget() void NetworkingLobby::init() { Screen::init(); - setInitialFocus(); m_start_button->setVisible(false); // For now create the active player and bind it to the right @@ -201,6 +200,18 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, StateManager::get()->escapePressed(); return; } + else if (name == m_player_list->m_properties[GUIEngine::PROP_ID]) + { + auto host_online_ids = StringUtils::splitToUInt + (m_player_list->getSelectionInternalName(), '_'); + if (host_online_ids.size() != 2 || + STKHost::get()->getMyHostId() == host_online_ids[0]) + { + return; + } + new NetworkUserDialog(host_online_ids[0], host_online_ids[1], + m_player_list->getSelectionLabel()); + } // click on replay file RibbonWidget* ribbon = dynamic_cast(widget); if (ribbon == NULL) return; @@ -227,6 +238,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, STKHost::get()->sendToServer(&start, true); } } + } // eventCallback // ---------------------------------------------------------------------------- @@ -243,23 +255,6 @@ bool NetworkingLobby::onEscapePressed() return true; // close the screen } // onEscapePressed -// ---------------------------------------------------------------------------- -void NetworkingLobby::onDisabledItemClicked(const std::string& item) -{ - -} // onDisabledItemClicked - -// ---------------------------------------------------------------------------- -void NetworkingLobby::setInitialFocus() -{ -} // setInitialFocus - -// ---------------------------------------------------------------------------- -void NetworkingLobby::onDialogClose() -{ - setInitialFocus(); -} // onDialogClose() - // ---------------------------------------------------------------------------- void NetworkingLobby::addPlayer(const std::tuple& p) @@ -273,7 +268,7 @@ void NetworkingLobby::addPlayer(const std::tuple(p)); m_player_list->addItem(internal_name, std::get<2>(p)); if (std::get<3>(p)) - m_player_list->markItemRed(internal_name, true); + m_player_list->markItemBlue(internal_name, true); } } // addPlayer diff --git a/src/states_screens/networking_lobby.hpp b/src/states_screens/networking_lobby.hpp index 84103bdf0..b2a1a3c15 100644 --- a/src/states_screens/networking_lobby.hpp +++ b/src/states_screens/networking_lobby.hpp @@ -34,11 +34,11 @@ namespace GUIEngine } /** - * \brief Handles the main menu + * \brief Handles the networking lobby * \ingroup states_screens */ -class NetworkingLobby : public GUIEngine::Screen, - public GUIEngine::ScreenSingleton +class NetworkingLobby : public GUIEngine::Screen, + public GUIEngine::ScreenSingleton { private: friend class GUIEngine::ScreenSingleton; @@ -55,9 +55,6 @@ private: GUIEngine::ListWidget *m_player_list; GUIEngine::TextBoxWidget* m_chat_box; - /** \brief Sets which widget has to be focused. Depends on the user state. */ - void setInitialFocus(); - public: virtual void onUpdate(float delta) OVERRIDE; @@ -81,12 +78,6 @@ public: /** \brief implement callback from parent class GUIEngine::Screen */ virtual bool onEscapePressed() OVERRIDE; - /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void onDisabledItemClicked(const std::string& item) OVERRIDE; - - /** \brief Implements the callback when a dialog gets closed. */ - virtual void onDialogClose() OVERRIDE; - /** Used to insert each client chat message (reserved). */ void addMoreServerInfo(const core::stringw& info); void setJoinedServer(std::shared_ptr server);