Initial GP in network

This commit is contained in:
Benau 2018-04-21 16:00:14 +08:00
parent 6728951985
commit ba681a7cf8
12 changed files with 300 additions and 99 deletions

View File

@ -363,6 +363,7 @@ void MainLoop::run()
GUIEngine::ModalDialog::dismiss();
if (World::getWorld())
{
race_manager->clearNetworkGrandPrixResult();
race_manager->exitRace();
}
if (!ProfileWorld::isNoGraphics())

View File

@ -19,6 +19,7 @@
#include "network/game_setup.hpp"
#include "config/player_manager.hpp"
#include "config/user_config.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
@ -28,6 +29,8 @@
#include "race/race_manager.hpp"
#include "utils/log.hpp"
#include <algorithm>
//-----------------------------------------------------------------------------
/** Update and see if any player disconnects.
* \param remove_disconnected_players remove the disconnected players,
@ -113,7 +116,10 @@ void GameSetup::addServerInfo(NetworkString* ns)
{
if (isGrandPrix())
{
ns->addUInt8((uint8_t)2).addUInt8((uint8_t)m_tracks.size())
uint8_t cur_track = (uint8_t)m_tracks.size();
if (!isGrandPrixStarted())
cur_track = 0;
ns->addUInt8((uint8_t)2).addUInt8(cur_track)
.addUInt8(getExtraServerInfo());
}
else
@ -129,3 +135,28 @@ void GameSetup::addServerInfo(NetworkString* ns)
}
ns->encodeString(NetworkConfig::get()->getMOTD());
} // addServerInfo
//-----------------------------------------------------------------------------
void GameSetup::sortPlayersForGrandPrix()
{
if (!isGrandPrix() || m_tracks.size() == 1)
return;
std::lock_guard<std::mutex> lock(m_players_mutex);
std::sort(m_players.begin(), m_players.end(),
[](const std::weak_ptr<NetworkPlayerProfile>& a,
const std::weak_ptr<NetworkPlayerProfile>& b)
{
// They should never expired
auto c = a.lock();
assert(c);
auto d = b.lock();
assert(d);
return (c->getScore() < d->getScore()) ||
(c->getScore() == d->getScore() &&
c->getOverallTime() > d->getOverallTime());
});
if (UserConfigParams::m_gp_most_points_first)
{
std::reverse(m_players.begin(), m_players.end());
}
} // sortPlayersForGrandPrix

View File

@ -118,7 +118,8 @@ public:
// ------------------------------------------------------------------------
void reset()
{
m_tracks.clear();
if (!isGrandPrixStarted())
m_tracks.clear();
m_laps = 0;
m_reverse = false;
}
@ -153,7 +154,17 @@ public:
return m_extra_server_info != 0;
}
// ------------------------------------------------------------------------
bool isGrandPrixStarted() const
{
return isGrandPrix() && !m_tracks.empty() &&
m_tracks.size() != getTotalGrandPrixTracks();
}
// ------------------------------------------------------------------------
void stopGrandPrix() { m_tracks.clear(); }
// ------------------------------------------------------------------------
const std::vector<std::string>& getAllTracks() const { return m_tracks; }
// ------------------------------------------------------------------------
void sortPlayersForGrandPrix();
};
#endif // GAME_SETUP_HPP

View File

@ -59,6 +59,12 @@ private:
/** The local player id relative to each peer. */
int m_local_player_id;
/** Score if grand prix. */
int m_score;
/** Overall time if grand prix. */
float m_overall_time;
public:
NetworkPlayerProfile(std::shared_ptr<STKPeer> peer,
const irr::core::stringw &name, uint32_t host_id,
@ -72,7 +78,8 @@ public:
m_default_kart_color = default_kart_color;
m_online_id = online_id;
m_per_player_difficulty = per_player_difficulty;
m_local_player_id = local_player_id;
m_local_player_id = local_player_id;
resetGrandPrixData();
}
// ------------------------------------------------------------------------
~NetworkPlayerProfile() {}
@ -80,33 +87,45 @@ public:
bool isLocalPlayer() const;
// ------------------------------------------------------------------------
/** Returns the host id of this player. */
uint32_t getHostId() const { return m_host_id; }
uint32_t getHostId() const { return m_host_id; }
// ------------------------------------------------------------------------
/** Sets the kart name for this player. */
void setKartName(const std::string &kart_name) { m_kart_name = kart_name; }
// ------------------------------------------------------------------------
/** Returns the name of the kart this player has selected. */
const std::string &getKartName() const { return m_kart_name; }
const std::string &getKartName() const { return m_kart_name; }
// ------------------------------------------------------------------------
/** Retuens the local player id for this player. */
int getLocalPlayerId() const { return m_local_player_id; }
int getLocalPlayerId() const { return m_local_player_id; }
// ------------------------------------------------------------------------
/** Returns the per-player difficulty. */
PerPlayerDifficulty getPerPlayerDifficulty() const
{
return m_per_player_difficulty;
} // getPerPlayerDifficulty
{ return m_per_player_difficulty; }
// ------------------------------------------------------------------------
/** Returns the name of this player. */
const irr::core::stringw& getName() const { return m_player_name; }
const irr::core::stringw& getName() const { return m_player_name; }
// ------------------------------------------------------------------------
float getDefaultKartColor() const { return m_default_kart_color; }
float getDefaultKartColor() const { return m_default_kart_color; }
// ------------------------------------------------------------------------
uint32_t getOnlineId() const { return m_online_id; }
uint32_t getOnlineId() const { return m_online_id; }
// ------------------------------------------------------------------------
bool isOfflineAccount() const { return m_online_id == 0; }
bool isOfflineAccount() const { return m_online_id == 0; }
// ------------------------------------------------------------------------
std::shared_ptr<STKPeer> getPeer() const { return m_peer.lock(); }
std::shared_ptr<STKPeer> getPeer() const { return m_peer.lock(); }
// ------------------------------------------------------------------------
int getScore() const { return m_score; }
// ------------------------------------------------------------------------
float getOverallTime() const { return m_overall_time; }
// ------------------------------------------------------------------------
void setScore(int score) { m_score = score; }
// ------------------------------------------------------------------------
void setOverallTime(float time) { m_overall_time = time; }
// ------------------------------------------------------------------------
void resetGrandPrixData()
{
m_score = 0;
m_overall_time = 0.0f;
}
}; // class NetworkPlayerProfile

View File

@ -320,35 +320,7 @@ void ClientLobby::update(int ticks)
break;
case CONNECTED:
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);
// In case of auto-connect, use random karts (or previous kart) from
// server and go to track selection (or grand prix later)
if (NetworkConfig::get()->isAutoConnect())
{
input_manager->setMasterPlayerOnly(true);
for (auto& p : NetworkConfig::get()->getNetworkPlayers())
{
StateManager::get()
->createActivePlayer(std::get<1>(p), std::get<0>(p));
}
input_manager->getDeviceManager()->setAssignMode(ASSIGN);
TracksScreen::getInstance()->setNetworkTracks();
TracksScreen::getInstance()->push();
}
else
{
screen->push();
}
m_state.store(SELECTING_KARTS);
}
break;
case SELECTING_KARTS:
case SELECTING_ASSETS:
break;
case PLAYING:
break;
@ -481,8 +453,8 @@ void ClientLobby::handleServerInfo(Event* event)
NetworkConfig::get()->setServerMode(u_data);
auto game_mode = NetworkConfig::get()->getLocalGameMode();
race_manager->setMinorMode(game_mode.first);
// We may use single mode in network even it's grand prix
//race_manager->setMajorMode(game_mode.second);
// We use single mode in network even it's grand prix
race_manager->setMajorMode(RaceManager::MAJOR_MODE_GRAND_PRIX);
//I18N: In the networking lobby
core::stringw mode_name = NetworkConfig::get()->getModeName(u_data);
@ -660,8 +632,8 @@ void ClientLobby::startingRaceNow()
*/
void ClientLobby::startSelection(Event* event)
{
m_state.store(KART_SELECTION);
const NetworkString& data = event->data();
uint8_t skip_kart_screen = data.getUInt8();
const unsigned kart_num = data.getUInt16();
const unsigned track_num = data.getUInt16();
m_available_karts.clear();
@ -678,7 +650,33 @@ void ClientLobby::startSelection(Event* event)
data.decodeString(&track);
m_available_tracks.insert(track);
}
Log::info("ClientLobby", "Kart selection starts now");
// In case the user opened a user info dialog
GUIEngine::ModalDialog::dismiss();
NetworkKartSelectionScreen* screen =
NetworkKartSelectionScreen::getInstance();
screen->setAvailableKartsFromServer(m_available_karts);
// In case of auto-connect or continue a grand prix, use random karts
// (or previous kart) from server and go to track selection
if (NetworkConfig::get()->isAutoConnect() || skip_kart_screen == 1)
{
input_manager->setMasterPlayerOnly(true);
for (auto& p : NetworkConfig::get()->getNetworkPlayers())
{
StateManager::get()
->createActivePlayer(std::get<1>(p), std::get<0>(p));
}
input_manager->getDeviceManager()->setAssignMode(ASSIGN);
TracksScreen::getInstance()->setNetworkTracks();
TracksScreen::getInstance()->push();
}
else
{
screen->push();
}
m_state.store(SELECTING_ASSETS);
Log::info("ClientLobby", "Selection starts now");
} // startSelection
//-----------------------------------------------------------------------------
@ -699,7 +697,9 @@ void ClientLobby::raceFinished(Event* event)
Log::info("ClientLobby", "Server notified that the race is finished.");
if (m_game_setup->isGrandPrix())
{
// fastest lap, and than each kart before / after grand prix points
int t = data.getUInt32();
static_cast<LinearWorld*>(World::getWorld())->setFastestLapTicks(t);
race_manager->configGrandPrixResultFromNetwork(data);
}
else if (race_manager->modeHasLaps())
{

View File

@ -35,8 +35,7 @@ private:
LINKED,
REQUESTING_CONNECTION,
CONNECTED, // means in the lobby room
KART_SELECTION, // Start kart selection, then go to next state
SELECTING_KARTS, // in the network kart selection screen
SELECTING_ASSETS, // in the kart selection or tracks screen
PLAYING, // racing
RACE_FINISHED, // race result shown
DONE,

View File

@ -107,6 +107,13 @@ ServerLobby::~ServerLobby()
void ServerLobby::setup()
{
LobbyProtocol::setup();
if (m_game_setup->isGrandPrix() && !m_game_setup->isGrandPrixStarted())
{
auto players = m_game_setup->getConnectedPlayers();
for (auto player : players)
player->resetGrandPrixData();
}
StateManager::get()->resetActivePlayers();
// We use maximum 16bit unsigned limit
auto all_k = kart_properties_manager->getAllAvailableKarts();
@ -266,6 +273,11 @@ void ServerLobby::asynchronousUpdate()
}
case REGISTER_SELF_ADDRESS:
{
if (m_game_setup->isGrandPrixStarted())
{
m_state = ACCEPTING_CLIENTS;
break;
}
// Register this server with the STK server. This will block
// this thread, but there is no need for the protocol manager
// to react to any requests before the server is registered.
@ -321,9 +333,11 @@ void ServerLobby::asynchronousUpdate()
case SELECTING:
if (m_timeout.load() < (float)StkTime::getRealTime())
{
std::lock_guard<std::mutex> lock(m_connection_mutex);
auto result = handleVote();
// Remove disconnected player (if any) one last time
m_game_setup->update(true);
m_game_setup->sortPlayersForGrandPrix();
auto players = m_game_setup->getConnectedPlayers();
NetworkString* load_world = getNetworkString();
load_world->setSynchronous(true);
@ -348,7 +362,6 @@ void ServerLobby::asynchronousUpdate()
}
load_world->encodeString(player->getKartName());
}
// TODO: sort players for grand prix here
configRemoteKart(players);
// Reset for next state usage
@ -382,6 +395,7 @@ void ServerLobby::update(int ticks)
stopCurrentRace();
}
std::lock_guard<std::mutex> lock(m_connection_mutex);
m_game_setup->stopGrandPrix();
m_state = NetworkConfig::get()->isLAN() ?
ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS;
setup();
@ -577,18 +591,18 @@ void ServerLobby::startSelection(const Event *event)
return;
}
if (NetworkConfig::get()->isWAN())
if (NetworkConfig::get()->isWAN() && m_server_registered)
{
assert(m_server_registered);
unregisterServer();
m_server_registered = false;
}
NetworkString *ns = getNetworkString(1);
// Start selection - must be synchronous since the receiver pushes
// a new screen, which must be donefrom the main thread.
// a new screen, which must be done from the main thread.
ns->setSynchronous(true);
ns->addUInt8(LE_START_SELECTION);
ns->addUInt8(LE_START_SELECTION).addUInt8(
m_game_setup->isGrandPrixStarted() ? 1 : 0);
// Remove karts / tracks from server that are not supported on all clients
std::set<std::string> karts_erase, tracks_erase;
@ -699,7 +713,36 @@ void ServerLobby::checkRaceFinished()
total->addUInt8(LE_RACE_FINISHED);
if (m_game_setup->isGrandPrix())
{
// fastest lap, and than each kart before / after grand prix points
// fastest lap
int fastest_lap =
static_cast<LinearWorld*>(World::getWorld())->getFastestLapTicks();
total->addUInt32(fastest_lap);
// all gp tracks
total->addUInt8((uint8_t)m_game_setup->getTotalGrandPrixTracks())
.addUInt8((uint8_t)m_game_setup->getAllTracks().size());
for (const std::string& gp_track : m_game_setup->getAllTracks())
total->encodeString(gp_track);
// each kart score and total time
auto& players = m_game_setup->getPlayers();
total->addUInt8((uint8_t)players.size());
for (unsigned i = 0; i < players.size(); i++)
{
int last_score = race_manager->getKartScore(i);
int cur_score = last_score;
float overall_time = race_manager->getOverallTime(i);
if (auto player = players[i].lock())
{
last_score = player->getScore();
cur_score += last_score;
overall_time = overall_time + player->getOverallTime();
player->setScore(cur_score);
player->setOverallTime(overall_time);
}
total->addUInt32(last_score).addUInt32(cur_score)
.addFloat(overall_time);
}
}
else if (race_manager->modeHasLaps())
{
@ -786,7 +829,8 @@ void ServerLobby::connectionRequested(Event* event)
const NetworkString &data = event->data();
// can we add the player ?
if (m_state != ACCEPTING_CLIENTS)
if (m_state != ACCEPTING_CLIENTS ||
m_game_setup->isGrandPrixStarted())
{
NetworkString *message = getNetworkString(2);
message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_BUSY);
@ -1054,7 +1098,7 @@ void ServerLobby::updateServerOwner()
void ServerLobby::kartSelectionRequested(Event* event)
{
std::lock_guard<std::mutex> lock(m_connection_mutex);
if (m_state != SELECTING)
if (m_state != SELECTING || m_game_setup->isGrandPrixStarted())
{
Log::warn("ServerLobby", "Received kart selection while in state %d.",
m_state.load());
@ -1284,3 +1328,10 @@ void ServerLobby::updateBanList()
m_ban_list[TransportAddress(ban.first).getIP()] = ban.second;
}
} // updateBanList
//-----------------------------------------------------------------------------
bool ServerLobby::waitingForPlayers() const
{
return m_state.load() == ACCEPTING_CLIENTS &&
!m_game_setup->isGrandPrixStarted();
} // waitingForPlayers

View File

@ -143,8 +143,7 @@ public:
void finishedLoadingWorld() OVERRIDE;
ServerState getCurrentState() const { return m_state.load(); }
void updateBanList();
virtual bool waitingForPlayers() const OVERRIDE
{ return m_state.load() == ACCEPTING_CLIENTS; }
virtual bool waitingForPlayers() const OVERRIDE;
virtual bool allPlayersReady() const OVERRIDE
{ return m_state.load() >= WAIT_FOR_RACE_STARTED; }

View File

@ -36,6 +36,12 @@ class Track;
*/
class GrandPrixData
{
protected:
/** The ident of the tracks in this grand prix in their right order, ident
* means the filename of the .track file without .track extension
* (ie. 'volcano'). */
std::vector<std::string> m_tracks;
public:
/** Used to classify GPs into groups */
enum GPGroupType
@ -57,11 +63,6 @@ private:
/** Original filename, only for error handling needed. */
std::string m_filename;
/** The ident of the tracks in this grand prix in their right order, ident
* means the filename of the .track file without .track extension
* (ie. 'volcano'). */
std::vector<std::string> m_tracks;
/** The number of laps that each track will be raced, in the right order */
std::vector<int> m_laps;
@ -105,7 +106,11 @@ public:
GrandPrixData(const std::string& filename, enum GPGroupType group);
/** Needed for simple creation of an instance of GrandPrixData */
GrandPrixData() {};
GrandPrixData() {}
virtual ~GrandPrixData() {}
virtual std::vector<std::string> getTrackNames(const bool includeLocked=false) const;
virtual unsigned int getNumberOfTracks(const bool includeLocked=false) const;
void changeTrackNumber(const unsigned int number_of_tracks,
const std::string& track_group);
@ -128,11 +133,9 @@ public:
bool writeToFile();
bool checkConsistency(bool log_error=true) const;
std::vector<std::string> getTrackNames(const bool includeLocked=false) const;
std::vector<int> getLaps(const bool includeLocked=false) const;
std::vector<bool> getReverse(const bool includeLocked=false) const;
bool isEditable() const;
unsigned int getNumberOfTracks(const bool includeLocked=false) const;
const std::string& getTrackId(const unsigned int track) const;
irr::core::stringw getTrackName(const unsigned int track) const;
unsigned int getLaps(const unsigned int track) const;

View File

@ -45,6 +45,7 @@
#include "modes/soccer_world.hpp"
#include "network/protocol_manager.hpp"
#include "network/network_config.hpp"
#include "network/network_string.hpp"
#include "network/protocols/lobby_protocol.hpp"
#include "network/race_event_manager.hpp"
#include "replay/replay_play.hpp"
@ -980,5 +981,70 @@ void RaceManager::startWatchingReplay(const std::string &track_ident,
} // startSingleRace
//-----------------------------------------------------------------------------
void RaceManager::configGrandPrixResultFromNetwork(NetworkString& ns)
{
setMajorMode(MAJOR_MODE_GRAND_PRIX);
class NetworkGrandPrixData : public GrandPrixData
{
public:
NetworkGrandPrixData() : GrandPrixData()
{ setGroup(GrandPrixData::GP_STANDARD); }
virtual std::vector<std::string>
getTrackNames(const bool includeLocked=false) const
{ return m_tracks; }
virtual unsigned int
getNumberOfTracks(const bool includeLocked=false) const
{ return m_tracks.size(); }
void addNetworkTrack(const std::string& t) { m_tracks.push_back(t); }
};
/* EOF */
NetworkGrandPrixData ngpd;
unsigned int track_size = ns.getUInt8();
unsigned int all_track_size = ns.getUInt8();
assert(all_track_size > 0);
m_track_number = all_track_size -1;
for (unsigned i = 0; i < all_track_size; i++)
{
std::string t;
ns.decodeString(&t);
ngpd.addNetworkTrack(t);
}
while (all_track_size < track_size)
{
ngpd.addNetworkTrack("");
all_track_size++;
}
m_tracks = ngpd.getTrackNames();
// For result screen we only need current lap and reserve
m_num_laps.resize(track_size, m_num_laps[0]);
m_reverse_track.resize(track_size, m_reverse_track[0]);
m_grand_prix = ngpd;
unsigned int player_size = ns.getUInt8();
assert(player_size == m_kart_status.size());
for (unsigned i = 0; i < player_size; i++)
{
int last_score = ns.getUInt32();
int cur_score = ns.getUInt32();
float overall_time = ns.getFloat();
m_kart_status[i].m_last_score = last_score;
m_kart_status[i].m_score = cur_score;
m_kart_status[i].m_overall_time = overall_time;
m_kart_status[i].m_gp_rank = i;
}
} // configGrandPrixResultFromNetwork
//-----------------------------------------------------------------------------
void RaceManager::clearNetworkGrandPrixResult()
{
if (m_major_mode != MAJOR_MODE_GRAND_PRIX)
return;
setMajorMode(MAJOR_MODE_SINGLE);
m_grand_prix = GrandPrixData();
m_track_number = 0;
m_tracks.clear();
m_num_laps.clear();
m_reverse_track.clear();
} // clearNetworkGrandPrixResult

View File

@ -36,6 +36,7 @@
#include "utils/vec3.hpp"
class AbstractKart;
class NetworkString;
class SavedGrandPrix;
class Track;
@ -303,7 +304,6 @@ private:
/** Stores remote kart information about all player karts. */
std::vector<RemoteKartInfo> m_player_karts;
std::vector<std::string> m_tracks;
std::vector<int> m_host_ids;
/** Number of local players. */
unsigned int m_num_local_players;
@ -786,6 +786,10 @@ public:
{
return m_num_spare_tire_karts;
} // getNumSpareTireKarts
// ------------------------------------------------------------------------
void configGrandPrixResultFromNetwork(NetworkString& ns);
// ------------------------------------------------------------------------
void clearNetworkGrandPrixResult();
}; // RaceManager

View File

@ -27,6 +27,7 @@
#include "graphics/2dutils.hpp"
#include "graphics/material.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/message_queue.hpp"
#include "guiengine/modaldialog.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/widget.hpp"
@ -89,7 +90,7 @@ void RaceResultGUI::init()
for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++)
{
const AbstractKart *kart = World::getWorld()->getKart(kart_id);
if (kart->getController()->isPlayerController())
if (kart->getController()->isLocalPlayerController())
human_win = human_win && kart->getRaceResult();
}
@ -250,6 +251,33 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
displayScreenShots();
}
// If we're playing online :
if (World::getWorld()->isNetworkWorld())
{
if (name == "middle") // Continue button (return to server lobby)
{
// Signal to the server that this client is back in the lobby now.
auto cl = LobbyProtocol::get<ClientLobby>();
if (cl)
cl->doneWithResults();
getWidget("middle")->setText(_("Waiting for others"));
}
if (name == "bottom") // Quit server (return to online lan / wan menu)
{
race_manager->clearNetworkGrandPrixResult();
if (STKHost::existHost())
{
STKHost::get()->shutdown();
}
race_manager->exitRace();
race_manager->setAIKartOverride("");
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->getResetScreens().data());
NetworkConfig::get()->unsetNetworking();
}
return;
}
// If something was unlocked, the 'continue' button was
// actually used to display "Show unlocked feature(s)" text.
// ---------------------------------------------------------
@ -330,32 +358,6 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
name.c_str());
}
// If we're playing online :
if (World::getWorld()->isNetworkWorld())
{
if (name == "middle") // Continue button (return to server lobby)
{
// Signal to the server that this client is back in the lobby now.
auto cl = LobbyProtocol::get<ClientLobby>();
if (cl)
cl->doneWithResults();
getWidget("middle")->setText(_("Waiting for others"));
}
if (name == "bottom") // Quit server (return to online lan / wan menu)
{
if (STKHost::existHost())
{
STKHost::get()->shutdown();
}
race_manager->exitRace();
race_manager->setAIKartOverride("");
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->getResetScreens().data());
NetworkConfig::get()->unsetNetworking();
}
return;
}
// Next check for GP
// -----------------
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
@ -426,9 +428,17 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
*/
void RaceResultGUI::backToLobby()
{
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX &&
race_manager->getTrackNumber() == race_manager->getNumOfTracks() - 1)
{
core::stringw msg = _("Network grand prix has been finished.");
MessageQueue::add(MessageQueue::MT_ACHIEVEMENT, msg);
}
race_manager->clearNetworkGrandPrixResult();
race_manager->exitRace();
race_manager->setAIKartOverride("");
GUIEngine::ModalDialog::dismiss();
cleanupGPProgress();
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->getResetScreens(true/*lobby*/).data());
} // backToLobby
@ -1467,9 +1477,16 @@ void RaceResultGUI::backToLobby()
("sshot_" + StringUtils::toString(n_sshot)).c_str());
GUIEngine::LabelWidget* label = getWidget<GUIEngine::LabelWidget>(
("sshot_label_" + StringUtils::toString(n_sshot)).c_str());
assert(track != NULL && sshot != NULL && label != NULL);
assert(sshot != NULL && label != NULL);
sshot->setImage(track->getScreenshotFile());
// Network grand prix chooses each track 1 bye 1
if (track == NULL)
{
sshot->setImage(file_manager->getAsset(FileManager::GUI,
"main_help.png"));
}
else
sshot->setImage(track->getScreenshotFile());
if (i <= currentTrack)
sshot->setBadge(GUIEngine::OK_BADGE);
else