Add network ingame dialog with chat function

This commit is contained in:
Benau 2019-01-13 16:59:26 +08:00
parent 9d42b70dda
commit 2bfa0f54dc
8 changed files with 153 additions and 50 deletions

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
<div x="1%" width="98%" height="fit" layout="horizontal-row">
<textbox id="chat" proportion="1"/>
<spacer width="3%" height="10"/>
<button id="send" width="20%" height="fit" align="center" I18N="In the network lobby" text="Send"/>
</div>
<spacer width="20" height="2%" />
<buttonbar id="backbtnribbon" proportion="4" width="100%" align="center">
<icon-button id="backbtn" width="128" height="128" align="center" icon="gui/icons/back.png"
extend_label="200" I18N="Race paused button" text="Back to Race"/>
</buttonbar>
<spacer width="20" height="8%" />
<buttonbar id="choiceribbon" proportion="4" width="100%" align="center">
<icon-button id="newrace" width="128" height="128" icon="gui/icons/main_race.png"
I18N="Show in network ingame dialog to allow user to go back to lobby to end spectating (for example)"
text="Back to lobby" word_wrap="true"/>
<icon-button id="restart" width="128" height="128" icon="gui/icons/restart.png"
I18N="Race paused button" text="Restart Race" word_wrap="true"/>
<icon-button id="endrace" width="128" height="128" icon="gui/icons/race_giveup.png"
I18N="Race paused button" text="Give Up Race" word_wrap="true"/>
<icon-button id="options" width="128" height="128" icon="gui/icons/main_options.png"
I18N="Race paused button" text="Options" word_wrap="true"/>
<icon-button id="help" width="128" height="128" icon="gui/icons/main_help.png"
I18N="Race paused button" text="Help" word_wrap="true"/>
<icon-button id="exit" width="128" height="128" icon="gui/icons/main_quit.png"
I18N="Race paused button" text="Exit Race" word_wrap="true"/>
</buttonbar>
<spacer width="20" height="35" />
</div>
</stkgui>

View File

@ -772,7 +772,10 @@ void ClientLobby::handleChat(Event* event)
Log::info("ClientLobby", "%s", StringUtils::wideToUtf8(message).c_str());
if (message.size() > 0)
{
NetworkingLobby::getInstance()->addMoreServerInfo(message);
if (GUIEngine::getCurrentScreen() == NetworkingLobby::getInstance())
NetworkingLobby::getInstance()->addMoreServerInfo(message);
else
MessageQueue::add(MessageQueue::MT_GENERIC, message);
}
} // handleChat
@ -1154,3 +1157,27 @@ void ClientLobby::startLiveJoinKartSelection()
->setAvailableKartsFromServer(karts);
NetworkKartSelectionScreen::getInstance()->push();
} // startLiveJoinKartSelection
// ----------------------------------------------------------------------------
void ClientLobby::sendChat(irr::core::stringw text)
{
text = text.trim().removeChars(L"\n\r");
if (text.size() > 0)
{
NetworkString* chat = getNetworkString();
chat->addUInt8(LobbyProtocol::LE_CHAT);
core::stringw name;
PlayerProfile* player = PlayerManager::getCurrentPlayer();
if (PlayerManager::getCurrentOnlineState() ==
PlayerProfile::OS_SIGNED_IN)
name = PlayerManager::getCurrentOnlineUserName();
else
name = player->getName();
chat->encodeString16(name + L": " + text);
STKHost::get()->sendToServer(chat, true);
delete chat;
}
} // sendChat

View File

@ -130,6 +130,7 @@ public:
void setSpectator(bool val) { m_spectator = val; }
bool isSpectator() const { return m_spectator; }
void startLiveJoinKartSelection();
void sendChat(irr::core::stringw text);
};
#endif // CLIENT_LOBBY_HPP

View File

@ -316,6 +316,7 @@ void ServerLobby::handleChat(Event* event)
{
if (!checkDataSize(event, 1)) return;
const bool sender_in_game = event->getPeer()->isWaitingForGame();
core::stringw message;
event->data().decodeString16(&message);
if (message.size() > 0)
@ -323,17 +324,19 @@ void ServerLobby::handleChat(Event* event)
NetworkString* chat = getNetworkString();
chat->setSynchronous(true);
chat->addUInt8(LE_CHAT).encodeString16(message);
// After game is started, only send to waiting player
const bool game_started = m_state.load() != WAITING_FOR_START_GAME;
STKHost::get()->sendPacketToAllPeersWith([game_started]
(STKPeer* p)
STKHost::get()->sendPacketToAllPeersWith(
[game_started, sender_in_game](STKPeer* p)
{
if (!p->isValidated())
return false;
if (!game_started)
return true;
if (!p->isWaitingForGame() && game_started)
return false;
if (game_started)
{
if (p->isWaitingForGame() && !sender_in_game)
return false;
if (!p->isWaitingForGame() && sender_in_game)
return false;
}
return true;
}, chat);
delete chat;

View File

@ -21,6 +21,7 @@
#include "audio/music_manager.hpp"
#include "audio/sfx_manager.hpp"
#include "config/user_config.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/widgets/icon_button_widget.hpp"
@ -28,7 +29,7 @@
#include "io/file_manager.hpp"
#include "modes/overworld.hpp"
#include "modes/world.hpp"
#include "network/protocols/lobby_protocol.hpp"
#include "network/protocols/client_lobby.hpp"
#include "network/network_config.hpp"
#include "network/network_string.hpp"
#include "network/stk_host.hpp"
@ -51,14 +52,19 @@ RacePausedDialog::RacePausedDialog(const float percentWidth,
const float percentHeight) :
ModalDialog(percentWidth, percentHeight)
{
m_self_destroy = false;
if (dynamic_cast<OverWorld*>(World::getWorld()) != NULL)
{
loadFromFile("overworld_dialog.stkgui");
}
else
else if (!NetworkConfig::get()->isNetworking())
{
loadFromFile("race_paused_dialog.stkgui");
}
else
{
loadFromFile("network_ingame_dialog.stkgui");
}
GUIEngine::RibbonWidget* back_btn = getWidget<RibbonWidget>("backbtnribbon");
back_btn->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
@ -67,6 +73,20 @@ RacePausedDialog::RacePausedDialog(const float percentWidth,
{
music_manager->pauseMusic();
SFXManager::get()->pauseAll();
m_text_box->clearListeners();
if (UserConfigParams::m_lobby_chat)
{
m_text_box->setActive(true);
getWidget("send")->setVisible(true);
m_text_box->addListener(this);
}
else
{
m_text_box->setActive(false);
m_text_box->setText(
_("Chat is disabled, enable in options menu."));
getWidget("send")->setVisible(false);
}
}
else
{
@ -137,7 +157,12 @@ GUIEngine::EventPropagation
GUIEngine::RibbonWidget* choice_ribbon =
getWidget<GUIEngine::RibbonWidget>("choiceribbon");
if (eventSource == "backbtnribbon")
if (eventSource == "send" && m_text_box)
{
onEnterPressed(m_text_box->getText());
return GUIEngine::EVENT_BLOCK;
}
else if (eventSource == "backbtnribbon")
{
// unpausing is done in the destructor so nothing more to do here
ModalDialog::dismiss();
@ -263,14 +288,16 @@ void RacePausedDialog::beforeAddingWidgets()
choice_ribbon->setItemVisible(index, false);
}
if (NetworkConfig::get()->isNetworking())
{
IconButtonWidget* new_race = dynamic_cast<IconButtonWidget*>
(choice_ribbon->findWidgetNamed("newrace"));
if (new_race)
{
//I18N: show in race paused dialog in network to allow user to go
//back to lobby to end spectating (for example)
new_race->setText(_("Back to lobby"));
}
}
m_text_box = getWidget<TextBoxWidget>("chat");
else
m_text_box = NULL;
} // beforeAddingWidgets
// ----------------------------------------------------------------------------
bool RacePausedDialog::onEnterPressed(const irr::core::stringw& text)
{
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->sendChat(text);
m_self_destroy = true;
return true;
} // onEnterPressed

View File

@ -19,20 +19,30 @@
#define HEADER_RACE_PAUSED_DIALOG_HPP
#include "guiengine/modaldialog.hpp"
#include "guiengine/widgets/text_box_widget.hpp"
#include "utils/cpp2011.hpp"
namespace GUIEngine
{
class RibbonWidget;
class TextBoxWidget;
}
/**
* \brief Dialog shown when the race is paused
* \ingroup states_screens
*/
class RacePausedDialog : public GUIEngine::ModalDialog
class RacePausedDialog : public GUIEngine::ModalDialog,
public GUIEngine::ITextBoxWidgetListener
{
private:
bool m_self_destroy;
GUIEngine::TextBoxWidget* m_text_box;
virtual void onTextUpdated() OVERRIDE {}
virtual bool onEnterPressed(const irr::core::stringw& text) OVERRIDE;
protected:
virtual void loadedFromFile() OVERRIDE;
@ -46,6 +56,16 @@ public:
GUIEngine::EventPropagation processEvent(const std::string& eventSource)
OVERRIDE;
virtual void beforeAddingWidgets() OVERRIDE;
// ------------------------------------------------------------------------
virtual void onUpdate(float dt) OVERRIDE
{
// It's unsafe to delete from inside the event handler so we do it here
if (m_self_destroy)
{
ModalDialog::dismiss();
return;
}
}
};
#endif

View File

@ -515,26 +515,12 @@ void NetworkingLobby::updatePlayerPings()
} // updatePlayerPings
// ----------------------------------------------------------------------------
void NetworkingLobby::sendChat(irr::core::stringw text)
bool NetworkingLobby::onEnterPressed(const irr::core::stringw& text)
{
text = text.trim().removeChars(L"\n\r");
if (text.size() > 0)
{
NetworkString chat(PROTOCOL_LOBBY_ROOM);
chat.addUInt8(LobbyProtocol::LE_CHAT);
core::stringw name;
PlayerProfile* player = PlayerManager::getCurrentPlayer();
if (PlayerManager::getCurrentOnlineState() ==
PlayerProfile::OS_SIGNED_IN)
name = PlayerManager::getCurrentOnlineUserName();
else
name = player->getName();
chat.encodeString16(name + L": " + text);
STKHost::get()->sendToServer(&chat, true);
}
} // sendChat
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->sendChat(text);
return true;
} // onEnterPressed
// ----------------------------------------------------------------------------
void NetworkingLobby::eventCallback(Widget* widget, const std::string& name,
@ -563,7 +549,8 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name,
} // click on a user
else if (name == m_send_button->m_properties[PROP_ID])
{
sendChat(m_chat_box->getText());
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->sendChat(m_chat_box->getText());
m_chat_box->setText("");
} // send chat message
else if (name == m_start_button->m_properties[PROP_ID])

View File

@ -102,13 +102,7 @@ private:
virtual void unloaded() OVERRIDE;
virtual void onTextUpdated() OVERRIDE {}
virtual bool onEnterPressed(const irr::core::stringw& text) OVERRIDE
{
sendChat(text);
return true;
}
void sendChat(irr::core::stringw text);
virtual bool onEnterPressed(const irr::core::stringw& text) OVERRIDE;
void updatePlayerPings();
public: