Allow player going back to lobby without disconnecting the server
This commit is contained in:
parent
641b16e1c7
commit
bb31d6b226
@ -101,6 +101,9 @@ public:
|
||||
void addLiveJoinPeer(std::weak_ptr<STKPeer> peer)
|
||||
{ m_last_confirmed_item_ticks[peer] = 0; }
|
||||
// ------------------------------------------------------------------------
|
||||
void erasePeerInGame(std::weak_ptr<STKPeer> peer)
|
||||
{ m_last_confirmed_item_ticks.erase(peer); }
|
||||
// ------------------------------------------------------------------------
|
||||
void saveCompleteState(BareNetworkString* buffer) const;
|
||||
// ------------------------------------------------------------------------
|
||||
void restoreCompleteState(const BareNetworkString& buffer);
|
||||
|
@ -18,8 +18,10 @@
|
||||
|
||||
#include "karts/kart_rewinder.hpp"
|
||||
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "guiengine/message_queue.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/explosion_animation.hpp"
|
||||
#include "karts/rescue_animation.hpp"
|
||||
@ -65,8 +67,6 @@ void KartRewinder::reset()
|
||||
m_has_server_state = false;
|
||||
} // reset
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function is called immediately before a rewind is done and saves
|
||||
* the current transform for the kart. The difference between this saved
|
||||
@ -110,6 +110,13 @@ void KartRewinder::computeError()
|
||||
{
|
||||
const int kartid = getWorldKartId();
|
||||
Log::debug("KartRewinder", "Kart id %d disconnected.", kartid);
|
||||
|
||||
SFXManager::get()->quickSound("appear");
|
||||
core::stringw player_name = getController()->getName();
|
||||
// I18N: Message shown in game to tell player left the game in network
|
||||
core::stringw msg = _("%s left the game.", player_name);
|
||||
|
||||
MessageQueue::add(MessageQueue::MT_FRIEND, msg);
|
||||
World::getWorld()->eliminateKart(kartid,
|
||||
false/*notify_of_elimination*/);
|
||||
setPosition(World::getWorld()->getCurrentNumKarts() + 1);
|
||||
|
@ -508,14 +508,18 @@ void ClientLobby::disconnectedPlayer(Event* event)
|
||||
if (!checkDataSize(event, 1)) return;
|
||||
|
||||
NetworkString &data = event->data();
|
||||
SFXManager::get()->quickSound("appear");
|
||||
unsigned disconnected_player_count = data.getUInt8();
|
||||
uint32_t host_id = data.getUInt32();
|
||||
m_peers_votes.erase(host_id);
|
||||
// If world exists the kart rewinder will know which player disconnects
|
||||
if (!World::getWorld())
|
||||
SFXManager::get()->quickSound("appear");
|
||||
for (unsigned i = 0; i < disconnected_player_count; i++)
|
||||
{
|
||||
std::string name;
|
||||
data.decodeString(&name);
|
||||
if (!World::getWorld())
|
||||
continue;
|
||||
core::stringw player_name = StringUtils::utf8ToWide(name);
|
||||
core::stringw msg = _("%s disconnected.", player_name);
|
||||
// Use the friend icon to avoid an error-like message
|
||||
@ -961,10 +965,14 @@ void ClientLobby::backToLobby(Event *event)
|
||||
m_auto_started = false;
|
||||
m_state.store(CONNECTED);
|
||||
|
||||
RaceEventManager::getInstance()->stop();
|
||||
auto gep = RaceEventManager::getInstance()->getProtocol();
|
||||
if (gep)
|
||||
gep->requestTerminate();
|
||||
if (RaceEventManager::getInstance())
|
||||
{
|
||||
RaceEventManager::getInstance()->stop();
|
||||
auto gep = RaceEventManager::getInstance()->getProtocol();
|
||||
// Game events protocol is main thread event only
|
||||
if (gep)
|
||||
gep->requestTerminate();
|
||||
}
|
||||
auto gp = GameProtocol::lock();
|
||||
if (gp)
|
||||
{
|
||||
|
@ -46,33 +46,34 @@ public:
|
||||
/** Lists all lobby events (LE). */
|
||||
enum : uint8_t
|
||||
{
|
||||
LE_CONNECTION_REQUESTED = 1, // a connection to the server
|
||||
LE_CONNECTION_REFUSED, // Connection to server refused
|
||||
LE_CONNECTION_ACCEPTED, // Connection to server accepted
|
||||
LE_SERVER_INFO, // inform client about server info
|
||||
LE_REQUEST_BEGIN, // begin of kart selection
|
||||
LE_UPDATE_PLAYER_LIST, // inform client about player list update
|
||||
LE_KART_SELECTION, // Player selected kart
|
||||
LE_PLAYER_DISCONNECTED, // Client disconnected
|
||||
LE_CLIENT_LOADED_WORLD, // Client finished loading world
|
||||
LE_LOAD_WORLD, // Clients should load world
|
||||
LE_START_RACE, // Server to client to start race
|
||||
LE_START_SELECTION, // inform client to start selection
|
||||
LE_RACE_FINISHED, // race has finished, display result
|
||||
LE_RACE_FINISHED_ACK, // client went back to lobby
|
||||
LE_BACK_LOBBY, // Force clients to go back to lobby
|
||||
LE_VOTE, // Track vote
|
||||
LE_CHAT,
|
||||
LE_SERVER_OWNERSHIP,
|
||||
LE_KICK_HOST,
|
||||
LE_CHANGE_TEAM,
|
||||
LE_BAD_TEAM,
|
||||
LE_BAD_CONNECTION,
|
||||
LE_CONFIG_SERVER,
|
||||
LE_CHANGE_HANDICAP,
|
||||
LE_LIVE_JOIN,
|
||||
LE_LIVE_JOIN_ACK,
|
||||
LE_KART_INFO
|
||||
LE_CONNECTION_REQUESTED = 1, // a connection to the server
|
||||
LE_CONNECTION_REFUSED, // Connection to server refused
|
||||
LE_CONNECTION_ACCEPTED, // Connection to server accepted
|
||||
LE_SERVER_INFO, // inform client about server info
|
||||
LE_REQUEST_BEGIN, // begin of kart selection
|
||||
LE_UPDATE_PLAYER_LIST, // inform client about player list update
|
||||
LE_KART_SELECTION, // Player selected kart
|
||||
LE_PLAYER_DISCONNECTED, // Client disconnected
|
||||
LE_CLIENT_LOADED_WORLD, // Client finished loading world
|
||||
LE_LOAD_WORLD, // Clients should load world
|
||||
LE_START_RACE, // Server to client to start race
|
||||
LE_START_SELECTION, // inform client to start selection
|
||||
LE_RACE_FINISHED, // race has finished, display result
|
||||
LE_RACE_FINISHED_ACK, // client went back to lobby
|
||||
LE_BACK_LOBBY, // Force clients to go back to lobby
|
||||
LE_VOTE, // Track vote
|
||||
LE_CHAT, // Client chat message
|
||||
LE_SERVER_OWNERSHIP, // Tell client he is now the server owner
|
||||
LE_KICK_HOST, // Server owner kicks some other peer in game
|
||||
LE_CHANGE_TEAM, // Client wants to change his team
|
||||
LE_BAD_TEAM, // Tell server owner that the team is unbalanced
|
||||
LE_BAD_CONNECTION, // High ping or too many packets loss
|
||||
LE_CONFIG_SERVER, // Server owner config server game mode or difficulty
|
||||
LE_CHANGE_HANDICAP, // Client changes handicap
|
||||
LE_LIVE_JOIN, // Client live join or spectate
|
||||
LE_LIVE_JOIN_ACK, // Server tell client live join or spectate succeed
|
||||
LE_KART_INFO, // Client or server exchange new kart info
|
||||
LE_CLIENT_BACK_LOBBY // Client tell server to go back lobby
|
||||
};
|
||||
|
||||
enum RejectReason : uint8_t
|
||||
|
@ -303,6 +303,7 @@ bool ServerLobby::notifyEvent(Event* event)
|
||||
case LE_LIVE_JOIN: liveJoinRequest(event); break;
|
||||
case LE_CLIENT_LOADED_WORLD: finishedLoadingLiveJoinClient(event); break;
|
||||
case LE_KART_INFO: handleKartInfo(event); break;
|
||||
case LE_CLIENT_BACK_LOBBY: clientWantsToBackLobby(event); break;
|
||||
default: Log::error("ServerLobby", "Unknown message type %d - ignored.",
|
||||
message_type);
|
||||
break;
|
||||
@ -656,15 +657,25 @@ NetworkString* ServerLobby::getLoadWorldMessage(
|
||||
} // getLoadWorldMessage
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns true if server can be live joined or spectating
|
||||
*/
|
||||
bool ServerLobby::canLiveJoinNow() const
|
||||
{
|
||||
return ServerConfig::m_live_players &&
|
||||
race_manager->supportsLiveJoining() &&
|
||||
World::getWorld() && RaceEventManager::getInstance()->isRunning() &&
|
||||
race_manager->supportsLiveJoining() && worldIsActive();
|
||||
} // canLiveJoinNow
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns true if world is active for clients to live join, spectate or
|
||||
* going back to lobby live
|
||||
*/
|
||||
bool ServerLobby::worldIsActive() const
|
||||
{
|
||||
return World::getWorld() && RaceEventManager::getInstance()->isRunning() &&
|
||||
!RaceEventManager::getInstance()->isRaceOver() &&
|
||||
(World::getWorld()->getPhase() == WorldStatus::RACE_PHASE ||
|
||||
World::getWorld()->getPhase() == WorldStatus::GOAL_PHASE);
|
||||
} // canLiveJoinNow
|
||||
} // worldIsActive
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** \ref STKPeer peer will be reset back to the lobby with reason
|
||||
@ -701,6 +712,7 @@ void ServerLobby::liveJoinRequest(Event* event)
|
||||
return;
|
||||
}
|
||||
bool spectator = data.getUInt8() == 1;
|
||||
peer->clearAvailableKartIDs();
|
||||
if (!spectator)
|
||||
{
|
||||
setPlayerKarts(data, peer);
|
||||
@ -728,7 +740,6 @@ void ServerLobby::liveJoinRequest(Event* event)
|
||||
return;
|
||||
}
|
||||
|
||||
peer->clearAvailableKartIDs();
|
||||
for (int id : used_id)
|
||||
{
|
||||
Log::info("ServerLobby", "%s live joining with reserved kart id %d.",
|
||||
@ -3352,6 +3363,9 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, STKPeer* peer) const
|
||||
} // setPlayerKarts
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Tell the client \ref RemoteKartInfo of a player when some player joining
|
||||
* live.
|
||||
*/
|
||||
void ServerLobby::handleKartInfo(Event* event)
|
||||
{
|
||||
World* w = World::getWorld();
|
||||
@ -3380,3 +3394,56 @@ void ServerLobby::handleKartInfo(Event* event)
|
||||
peer->sendPacket(ns, true/*reliable*/);
|
||||
delete ns;
|
||||
} // handleKartInfo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Client if currently in-game (including spectator) wants to go back to
|
||||
* lobby.
|
||||
*/
|
||||
void ServerLobby::clientWantsToBackLobby(Event* event)
|
||||
{
|
||||
World* w = World::getWorld();
|
||||
std::shared_ptr<STKPeer> peer = event->getPeerSP();
|
||||
|
||||
if (!w || !worldIsActive() || peer->isWaitingForGame())
|
||||
{
|
||||
Log::warn("ServerLobby", "%s try to leave the game at wrong time.",
|
||||
peer->getAddress().toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (const int id : peer->getAvailableKartIDs())
|
||||
{
|
||||
RemoteKartInfo& rki = race_manager->getKartInfo(id);
|
||||
if (rki.getHostId() == peer->getHostId())
|
||||
{
|
||||
Log::info("ServerLobby", "%s left the game with kart id %d.",
|
||||
peer->getAddress().toString().c_str(), id);
|
||||
rki.setNetworkPlayerProfile(
|
||||
std::shared_ptr<NetworkPlayerProfile>());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("ServerLobby", "%s doesn't exist anymore in server.",
|
||||
peer->getAddress().toString().c_str());
|
||||
}
|
||||
}
|
||||
NetworkItemManager* nim =
|
||||
dynamic_cast<NetworkItemManager*>(ItemManager::get());
|
||||
assert(nim);
|
||||
nim->erasePeerInGame(peer);
|
||||
m_peers_ready.erase(peer);
|
||||
peer->setWaitingForGame(true);
|
||||
|
||||
NetworkString* reset = getNetworkString(2);
|
||||
reset->setSynchronous(true);
|
||||
reset->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE);
|
||||
peer->sendPacket(reset, /*reliable*/true);
|
||||
delete reset;
|
||||
updatePlayerList();
|
||||
NetworkString* server_info = getNetworkString();
|
||||
server_info->setSynchronous(true);
|
||||
server_info->addUInt8(LE_SERVER_INFO);
|
||||
m_game_setup->addServerInfo(server_info);
|
||||
peer->sendPacket(server_info, /*reliable*/true);
|
||||
delete server_info;
|
||||
} // clientWantsToBackLobby
|
||||
|
@ -279,9 +279,11 @@ private:
|
||||
void liveJoinRequest(Event* event);
|
||||
void rejectLiveJoin(STKPeer* peer, BackLobbyReason blr);
|
||||
bool canLiveJoinNow() const;
|
||||
bool worldIsActive() const;
|
||||
int getReservedId(std::shared_ptr<NetworkPlayerProfile>& p,
|
||||
unsigned local_id) const;
|
||||
void handleKartInfo(Event* event);
|
||||
void clientWantsToBackLobby(Event* event);
|
||||
public:
|
||||
ServerLobby();
|
||||
virtual ~ServerLobby();
|
||||
|
@ -28,7 +28,9 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/protocols/lobby_protocol.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "states_screens/help_screen_1.hpp"
|
||||
@ -155,14 +157,21 @@ GUIEngine::EventPropagation
|
||||
}
|
||||
race_manager->exitRace();
|
||||
race_manager->setAIKartOverride("");
|
||||
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
|
||||
|
||||
if (race_manager->raceWasStartedFromOverworld())
|
||||
if (NetworkConfig::get()->isNetworking())
|
||||
{
|
||||
OverWorld::enterOverWorld();
|
||||
StateManager::get()->resetAndSetStack(
|
||||
NetworkConfig::get()->getResetScreens().data());
|
||||
NetworkConfig::get()->unsetNetworking();
|
||||
}
|
||||
else
|
||||
{
|
||||
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
|
||||
if (race_manager->raceWasStartedFromOverworld())
|
||||
{
|
||||
OverWorld::enterOverWorld();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkConfig::get()->unsetNetworking();
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
else if (selection == "help")
|
||||
@ -187,23 +196,26 @@ GUIEngine::EventPropagation
|
||||
else if (selection == "newrace")
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
if (STKHost::existHost())
|
||||
if (NetworkConfig::get()->isNetworking())
|
||||
{
|
||||
STKHost::get()->shutdown();
|
||||
// back lobby
|
||||
NetworkString back(PROTOCOL_LOBBY_ROOM);
|
||||
back.setSynchronous(true);
|
||||
back.addUInt8(LobbyProtocol::LE_CLIENT_BACK_LOBBY);
|
||||
STKHost::get()->sendToServer(&back, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
World::getWorld()->scheduleUnpause();
|
||||
race_manager->exitRace();
|
||||
Screen* new_stack[] =
|
||||
{
|
||||
MainMenuScreen::getInstance(),
|
||||
RaceSetupScreen::getInstance(),
|
||||
NULL
|
||||
};
|
||||
StateManager::get()->resetAndSetStack(new_stack);
|
||||
}
|
||||
World::getWorld()->scheduleUnpause();
|
||||
race_manager->exitRace();
|
||||
Screen* new_stack[] =
|
||||
{
|
||||
MainMenuScreen::getInstance(),
|
||||
RaceSetupScreen::getInstance(),
|
||||
NULL
|
||||
};
|
||||
StateManager::get()->resetAndSetStack(
|
||||
NetworkConfig::get()->isNetworking() ?
|
||||
NetworkConfig::get()->getResetScreens().data() :
|
||||
new_stack);
|
||||
NetworkConfig::get()->unsetNetworking();
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
else if (selection == "endrace")
|
||||
@ -224,7 +236,6 @@ GUIEngine::EventPropagation
|
||||
} // processEvent
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void RacePausedDialog::beforeAddingWidgets()
|
||||
{
|
||||
GUIEngine::RibbonWidget* choice_ribbon =
|
||||
@ -238,7 +249,8 @@ void RacePausedDialog::beforeAddingWidgets()
|
||||
// Disable in game menu to avoid timer desync if not racing in network
|
||||
// game
|
||||
if (NetworkConfig::get()->isNetworking() &&
|
||||
World::getWorld()->getPhase() != WorldStatus::RACE_PHASE)
|
||||
!(World::getWorld()->getPhase() == WorldStatus::MUSIC_PHASE ||
|
||||
World::getWorld()->getPhase() == WorldStatus::RACE_PHASE))
|
||||
{
|
||||
index = choice_ribbon->findItemNamed("help");
|
||||
if (index != -1)
|
||||
@ -246,8 +258,19 @@ void RacePausedDialog::beforeAddingWidgets()
|
||||
index = choice_ribbon->findItemNamed("options");
|
||||
if (index != -1)
|
||||
choice_ribbon->setItemVisible(index, false);
|
||||
index = choice_ribbon->findItemNamed("newrace");
|
||||
if (index != -1)
|
||||
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"));
|
||||
}
|
||||
}
|
||||
} // beforeAddingWidgets
|
||||
|
Loading…
x
Reference in New Issue
Block a user