Add live join and spectate button to lobby

This commit is contained in:
Benau 2019-01-04 23:56:50 +08:00
parent 582ec771c0
commit 2950238d2b
9 changed files with 151 additions and 38 deletions

View File

@ -253,12 +253,15 @@ void World::init()
if (Camera::getNumCameras() == 0) if (Camera::getNumCameras() == 0)
{ {
auto cl = LobbyProtocol::get<ClientLobby>();
if ( (NetworkConfig::get()->isServer() && if ( (NetworkConfig::get()->isServer() &&
!ProfileWorld::isNoGraphics() ) || !ProfileWorld::isNoGraphics() ) ||
race_manager->isWatchingReplay() ) race_manager->isWatchingReplay() ||
(cl && cl->isSpectator()))
{ {
// In case that the server is running with gui or watching replay, // In case that the server is running with gui, watching replay or
// create a camera and attach it to the first kart. // spectating the game, create a camera and attach it to the first
// kart.
Camera::createCamera(World::getWorld()->getKart(0), 0); Camera::createCamera(World::getWorld()->getKart(0), 0);
} // if server with graphics of is watching replay } // if server with graphics of is watching replay

View File

@ -155,6 +155,7 @@ void GameSetup::addServerInfo(NetworkString* ns)
ns->encodeString16(m_message_of_today); ns->encodeString16(m_message_of_today);
ns->addUInt8((uint8_t)ServerConfig::m_server_configurable); ns->addUInt8((uint8_t)ServerConfig::m_server_configurable);
ns->addUInt8(race_manager->supportsLiveJoining() ? 1 : 0);
} // addServerInfo } // addServerInfo
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -29,6 +29,7 @@
#include "items/powerup_manager.hpp" #include "items/powerup_manager.hpp"
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp" #include "karts/controller/controller.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp" #include "karts/kart_properties_manager.hpp"
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "network/crypto.hpp" #include "network/crypto.hpp"
@ -91,6 +92,7 @@ ClientLobby::ClientLobby(const TransportAddress& a, std::shared_ptr<Server> s)
m_disconnected_msg[PDI_BAD_CONNECTION] = m_disconnected_msg[PDI_BAD_CONNECTION] =
_("Bad network connection is detected."); _("Bad network connection is detected.");
m_first_connect = true; m_first_connect = true;
m_spectator = false;
} // ClientLobby } // ClientLobby
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -110,6 +112,7 @@ ClientLobby::~ClientLobby()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ClientLobby::setup() void ClientLobby::setup()
{ {
m_spectator = false;
m_auto_back_to_lobby_time = std::numeric_limits<uint64_t>::max(); m_auto_back_to_lobby_time = std::numeric_limits<uint64_t>::max();
m_start_live_game_time = std::numeric_limits<uint64_t>::max(); m_start_live_game_time = std::numeric_limits<uint64_t>::max();
m_received_server_result = false; m_received_server_result = false;
@ -649,6 +652,9 @@ void ClientLobby::handleServerInfo(Event* event)
} }
bool server_config = data.getUInt8() == 1; bool server_config = data.getUInt8() == 1;
NetworkingLobby::getInstance()->toggleServerConfigButton(server_config); NetworkingLobby::getInstance()->toggleServerConfigButton(server_config);
bool live_join_spectator = data.getUInt8() == 1;
NetworkingLobby::getInstance()
->toggleServerLiveJoinable(live_join_spectator);
} // handleServerInfo } // handleServerInfo
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1101,3 +1107,21 @@ void ClientLobby::handleKartInfo(Event* event)
SFXManager::get()->quickSound("energy_bar_full"); SFXManager::get()->quickSound("energy_bar_full");
MessageQueue::add(MessageQueue::MT_FRIEND, msg); MessageQueue::add(MessageQueue::MT_FRIEND, msg);
} // handleKartInfo } // handleKartInfo
//-----------------------------------------------------------------------------
void ClientLobby::startLiveJoinKartSelection()
{
NetworkKartSelectionScreen::getInstance()->setLiveJoin(true);
std::vector<int> all_k =
kart_properties_manager->getKartsInGroup("standard");
std::set<std::string> karts;
for (int kart : all_k)
{
const KartProperties* kp = kart_properties_manager->getKartById(kart);
if (!kp->isAddon())
karts.insert(kp->getIdent());
}
NetworkKartSelectionScreen::getInstance()
->setAvailableKartsFromServer(karts);
NetworkKartSelectionScreen::getInstance()->push();
} // startLiveJoinKartSelection

View File

@ -79,6 +79,8 @@ private:
bool m_first_connect; bool m_first_connect;
bool m_spectator;
uint64_t m_auto_back_to_lobby_time; uint64_t m_auto_back_to_lobby_time;
uint64_t m_start_live_game_time; uint64_t m_start_live_game_time;
@ -125,6 +127,9 @@ public:
bool isServerAutoGameTime() const { return m_server_auto_game_time; } bool isServerAutoGameTime() const { return m_server_auto_game_time; }
virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; } virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; }
void requestKartInfo(uint8_t kart_id); void requestKartInfo(uint8_t kart_id);
void setSpectator(bool val) { m_spectator = val; }
bool isSpectator() const { return m_spectator; }
void startLiveJoinKartSelection();
}; };
#endif // CLIENT_LOBBY_HPP #endif // CLIENT_LOBBY_HPP

View File

@ -174,7 +174,8 @@ void GameProtocol::controllerAction(int kart_id, PlayerAction action,
void GameProtocol::handleControllerAction(Event *event) void GameProtocol::handleControllerAction(Event *event)
{ {
STKPeer* peer = event->getPeer(); STKPeer* peer = event->getPeer();
if (NetworkConfig::get()->isServer() && peer->isWaitingForGame()) if (NetworkConfig::get()->isServer() && (peer->isWaitingForGame() ||
peer->getAvailableKartIDs().empty()))
return; return;
NetworkString &data = event->data(); NetworkString &data = event->data();
uint8_t count = data.getUInt8(); uint8_t count = data.getUInt8();

View File

@ -696,6 +696,9 @@ void ServerLobby::liveJoinRequest(Event* event)
rejectLiveJoin(peer, BLR_NO_GAME_FOR_LIVE_JOIN); rejectLiveJoin(peer, BLR_NO_GAME_FOR_LIVE_JOIN);
return; return;
} }
bool spectator = data.getUInt8() == 1;
if (!spectator)
{
setPlayerKarts(data, peer); setPlayerKarts(data, peer);
std::vector<int> used_id; std::vector<int> used_id;
@ -728,6 +731,13 @@ void ServerLobby::liveJoinRequest(Event* event)
peer->getAddress().toString().c_str(), id); peer->getAddress().toString().c_str(), id);
peer->addAvailableKartID(id); peer->addAvailableKartID(id);
} }
}
else
{
Log::info("ServerLobby", "%s spectating now.",
peer->getAddress().toString().c_str());
}
std::vector<std::shared_ptr<NetworkPlayerProfile> > players; std::vector<std::shared_ptr<NetworkPlayerProfile> > players;
for (unsigned i = 0; i < race_manager->getNumPlayers(); i++) for (unsigned i = 0; i < race_manager->getNumPlayers(); i++)
{ {
@ -856,9 +866,14 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event)
World::getWorld()->addReservedKart(id); World::getWorld()->addReservedKart(id);
const RemoteKartInfo& rki = race_manager->getKartInfo(id); const RemoteKartInfo& rki = race_manager->getKartInfo(id);
addLiveJoiningKart(id, rki, m_last_live_join_util_ticks); addLiveJoiningKart(id, rki, m_last_live_join_util_ticks);
Log::info("ServerLobby", "%s live-joining succeeded with kart id %d.",
peer->getAddress().toString().c_str(), id);
} }
Log::info("ServerLobby", "%s live-joining succeeded.", if (peer->getAvailableKartIDs().empty())
{
Log::info("ServerLobby", "%s spectating succeeded.",
peer->getAddress().toString().c_str()); peer->getAddress().toString().c_str());
}
NetworkString* ns = getNetworkString(10); NetworkString* ns = getNetworkString(10);
ns->setSynchronous(true); ns->setSynchronous(true);

View File

@ -104,7 +104,9 @@ void NetworkKartSelectionScreen::allPlayersDone()
if (m_live_join) if (m_live_join)
{ {
kart.setSynchronous(true); kart.setSynchronous(true);
kart.addUInt8(LobbyProtocol::LE_LIVE_JOIN); kart.addUInt8(LobbyProtocol::LE_LIVE_JOIN)
// not spectator
.addUInt8(0);
} }
else else
kart.addUInt8(LobbyProtocol::LE_KART_SELECTION); kart.addUInt8(LobbyProtocol::LE_KART_SELECTION);

View File

@ -41,6 +41,7 @@
#include "network/protocols/client_lobby.hpp" #include "network/protocols/client_lobby.hpp"
#include "network/server.hpp" #include "network/server.hpp"
#include "network/stk_host.hpp" #include "network/stk_host.hpp"
#include "network/network_timer_synchronizer.hpp"
#include "states_screens/dialogs/splitscreen_player_dialog.hpp" #include "states_screens/dialogs/splitscreen_player_dialog.hpp"
#include "states_screens/dialogs/network_user_dialog.hpp" #include "states_screens/dialogs/network_user_dialog.hpp"
#include "states_screens/dialogs/server_configuration_dialog.hpp" #include "states_screens/dialogs/server_configuration_dialog.hpp"
@ -122,6 +123,10 @@ void NetworkingLobby::loadedFromFile()
(file_manager->getAsset(FileManager::GUI_ICON, "hourglass.png")); (file_manager->getAsset(FileManager::GUI_ICON, "hourglass.png"));
video::ITexture* icon_5 = irr_driver->getTexture video::ITexture* icon_5 = irr_driver->getTexture
(file_manager->getAsset(FileManager::GUI_ICON, "green_check.png")); (file_manager->getAsset(FileManager::GUI_ICON, "green_check.png"));
m_config_texture = irr_driver->getTexture
(file_manager->getAsset(FileManager::GUI_ICON, "main_options.png"));
m_spectate_texture = irr_driver->getTexture
(file_manager->getAsset(FileManager::GUI_ICON, "screen_other.png"));
m_icon_bank->addTextureAsSprite(icon_1); m_icon_bank->addTextureAsSprite(icon_1);
m_icon_bank->addTextureAsSprite(icon_2); m_icon_bank->addTextureAsSprite(icon_2);
m_icon_bank->addTextureAsSprite(icon_3); m_icon_bank->addTextureAsSprite(icon_3);
@ -161,6 +166,8 @@ void NetworkingLobby::init()
m_player_names.clear(); m_player_names.clear();
m_allow_change_team = false; m_allow_change_team = false;
m_has_auto_start_in_server = false; m_has_auto_start_in_server = false;
m_server_live_joinable = false;
m_client_live_joinable = false;
m_ping_update_timer = 0.0f; m_ping_update_timer = 0.0f;
m_start_timeout = std::numeric_limits<float>::max(); m_start_timeout = std::numeric_limits<float>::max();
m_cur_starting_timer = std::numeric_limits<int64_t>::max(); m_cur_starting_timer = std::numeric_limits<int64_t>::max();
@ -248,6 +255,11 @@ void NetworkingLobby::onUpdate(float delta)
if (NetworkConfig::get()->isServer() || !STKHost::existHost()) if (NetworkConfig::get()->isServer() || !STKHost::existHost())
return; return;
m_start_button->setVisible(false);
m_config_button->setVisible(false);
m_config_button->setImage(m_config_texture);
m_client_live_joinable = false;
m_ping_update_timer += delta; m_ping_update_timer += delta;
if (m_player_list && m_ping_update_timer > 2.0f) if (m_player_list && m_ping_update_timer > 2.0f)
{ {
@ -317,6 +329,18 @@ void NetworkingLobby::onUpdate(float delta)
//wait before the current game finish //wait before the current game finish
msg = _("Please wait for the current game's end."); msg = _("Please wait for the current game's end.");
} }
// You can live join or spectator if u have the current play track
// and network timer is synchronized
if (t &&
STKHost::get()->getNetworkTimerSynchronizer()->isSynchronised() &&
m_server_live_joinable)
{
m_client_live_joinable = true;
}
else
m_client_live_joinable = false;
m_timeout_message->setText(msg, false); m_timeout_message->setText(msg, false);
core::stringw total_msg; core::stringw total_msg;
for (auto& string : m_server_info) for (auto& string : m_server_info)
@ -326,6 +350,19 @@ void NetworkingLobby::onUpdate(float delta)
} }
m_text_bubble->setText(total_msg, true); m_text_bubble->setText(total_msg, true);
m_cur_starting_timer = std::numeric_limits<int64_t>::max(); m_cur_starting_timer = std::numeric_limits<int64_t>::max();
if (m_client_live_joinable)
{
m_start_button->setVisible(true);
//I18N: Live join is displayed in networking lobby to allow players
//to join the current started in-progress game
m_start_button->setLabel(_("Live join"));
//I18N: Spectate is displayed in networking lobby to allow players
//to join the current started in-progress game
m_config_button->setLabel(_("Spectate"));
m_config_button->setImage(m_spectate_texture);
m_config_button->setVisible(true);
}
return; return;
} }
@ -508,15 +545,35 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name,
m_chat_box->setText(""); m_chat_box->setText("");
} // send chat message } // send chat message
else if (name == m_start_button->m_properties[PROP_ID]) else if (name == m_start_button->m_properties[PROP_ID])
{
if (m_client_live_joinable)
{
auto cl = LobbyProtocol::get<ClientLobby>();
if (cl)
cl->startLiveJoinKartSelection();
}
else
{ {
// Send a message to the server to start // Send a message to the server to start
NetworkString start(PROTOCOL_LOBBY_ROOM); NetworkString start(PROTOCOL_LOBBY_ROOM);
start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN); start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN);
STKHost::get()->sendToServer(&start, true); STKHost::get()->sendToServer(&start, true);
} }
}
else if (name == m_config_button->m_properties[PROP_ID]) else if (name == m_config_button->m_properties[PROP_ID])
{ {
auto cl = LobbyProtocol::get<ClientLobby>(); auto cl = LobbyProtocol::get<ClientLobby>();
if (m_client_live_joinable && cl)
{
cl->setSpectator(true);
NetworkString start(PROTOCOL_LOBBY_ROOM);
start.setSynchronous(true);
start.addUInt8(LobbyProtocol::LE_LIVE_JOIN)
// is spectating
.addUInt8(1);
STKHost::get()->sendToServer(&start, true);
return;
}
if (cl) if (cl)
{ {
new ServerConfigurationDialog( new ServerConfigurationDialog(

View File

@ -77,7 +77,11 @@ private:
unsigned m_min_start_game_players; unsigned m_min_start_game_players;
bool m_allow_change_team, m_has_auto_start_in_server, bool m_allow_change_team, m_has_auto_start_in_server,
m_server_configurable; m_server_configurable, m_server_live_joinable,
m_client_live_joinable;
video::ITexture* m_config_texture;
video::ITexture* m_spectate_texture;
GUIEngine::IconButtonWidget* m_back_widget; GUIEngine::IconButtonWidget* m_back_widget;
GUIEngine::LabelWidget* m_header; GUIEngine::LabelWidget* m_header;
@ -145,6 +149,7 @@ public:
float start_timeout, unsigned server_max_player); float start_timeout, unsigned server_max_player);
void setStartingTimerTo(float t); void setStartingTimerTo(float t);
void toggleServerConfigButton(bool val) { m_server_configurable = val; } void toggleServerConfigButton(bool val) { m_server_configurable = val; }
void toggleServerLiveJoinable(bool val) { m_server_live_joinable = val; }
}; // class NetworkingLobby }; // class NetworkingLobby
#endif #endif