Allow install addons live in lobby

This commit is contained in:
Benau 2019-11-30 02:03:56 +08:00
parent 19d008d0f8
commit a962954c5e
11 changed files with 235 additions and 98 deletions

View File

@ -52,6 +52,7 @@
#include "network/stk_peer.hpp"
#include "online/online_profile.hpp"
#include "online/xml_request.hpp"
#include "states_screens/dialogs/addons_pack.hpp"
#include "states_screens/online/networking_lobby.hpp"
#include "states_screens/online/network_kart_selection.hpp"
#include "states_screens/race_result_gui.hpp"
@ -372,21 +373,7 @@ void ClientLobby::update(int ticks)
for (const std::string& cap : stk_config->m_network_capabilities)
ns->encodeString(cap);
auto all_k = kart_properties_manager->getAllAvailableKarts();
auto all_t = track_manager->getAllTrackIdentifiers();
if (all_k.size() >= 65536)
all_k.resize(65535);
if (all_t.size() >= 65536)
all_t.resize(65535);
ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size());
for (const std::string& kart : all_k)
{
ns->encodeString(kart);
}
for (const std::string& track : all_t)
{
ns->encodeString(track);
}
getKartsTracksNetworkString(ns);
assert(!NetworkConfig::get()->isAddingNetworkPlayers());
const uint8_t player_count =
(uint8_t)NetworkConfig::get()->getNetworkPlayers().size();
@ -1511,3 +1498,55 @@ void ClientLobby::reportSuccess(Event* event)
MessageQueue::add(MessageQueue::MT_GENERIC, msg);
}
} // reportSuccess
// ----------------------------------------------------------------------------
void ClientLobby::handleClientCommand(const std::string& cmd)
{
#ifndef SERVER_ONLY
auto argv = StringUtils::split(cmd, ' ');
if (argv.size() == 0)
return;
if (argv[0] == "installaddon" && argv.size() == 2)
AddonsPack::install(argv[1]);
else if (argv[0] == "uninstalladdon" && argv.size() == 2)
AddonsPack::uninstall(argv[1]);
else
{
// Send for server command
NetworkString* cmd_ns = getNetworkString(1);
cmd_ns->addUInt8(LE_COMMAND).encodeString(cmd);
sendToServer(cmd_ns, /*reliable*/true);
delete cmd_ns;
}
#endif
} // handleClientCommand
// ----------------------------------------------------------------------------
void ClientLobby::getKartsTracksNetworkString(BareNetworkString* ns)
{
auto all_k = kart_properties_manager->getAllAvailableKarts();
auto all_t = track_manager->getAllTrackIdentifiers();
if (all_k.size() >= 65536)
all_k.resize(65535);
if (all_t.size() >= 65536)
all_t.resize(65535);
ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size());
for (const std::string& kart : all_k)
{
ns->encodeString(kart);
}
for (const std::string& track : all_t)
{
ns->encodeString(track);
}
} // getKartsTracksNetworkString
// ----------------------------------------------------------------------------
void ClientLobby::updateAssetsToServer()
{
NetworkString* ns = getNetworkString(1);
ns->addUInt8(LE_ASSETS_UPDATE);
getKartsTracksNetworkString(ns);
sendToServer(ns, /*reliable*/true);
delete ns;
} // updateAssetsToServer

View File

@ -139,6 +139,7 @@ private:
decodePlayers(const BareNetworkString& data,
std::shared_ptr<STKPeer> peer = nullptr,
bool* is_spectator = NULL) const;
void getKartsTracksNetworkString(BareNetworkString* ns);
public:
ClientLobby(const TransportAddress& a, std::shared_ptr<Server> s);
virtual ~ClientLobby();
@ -182,6 +183,8 @@ public:
{ return m_server_enabled_report_player; }
const std::vector<float>& getRankingChanges() const
{ return m_ranking_changes; }
void handleClientCommand(const std::string& cmd);
void updateAssetsToServer();
};
#endif // CLIENT_LOBBY_HPP

View File

@ -74,8 +74,10 @@ public:
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
LE_REPORT_PLAYER // Client report some player in server
LE_REPORT_PLAYER, // Client report some player in server
// (like abusive behaviour)
LE_ASSETS_UPDATE, // Client tell server with updated assets
LE_COMMAND, // Command
};
enum RejectReason : uint8_t

View File

@ -755,6 +755,8 @@ bool ServerLobby::notifyEventAsynchronous(Event* event)
case LE_CLIENT_BACK_LOBBY:
clientSelectingAssetsWantsToBackLobby(event); break;
case LE_REPORT_PLAYER: writePlayerReport(event); break;
case LE_ASSETS_UPDATE:
handleAssets(event->data(), event->getPeer()); break;
default: break;
} // switch
} // if (event->getType() == EVENT_TYPE_MESSAGE)
@ -2914,72 +2916,21 @@ void ServerLobby::saveIPBanTable(const TransportAddress& addr)
} // saveIPBanTable
//-----------------------------------------------------------------------------
void ServerLobby::connectionRequested(Event* event)
bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) const
{
std::shared_ptr<STKPeer> peer = event->getPeerSP();
NetworkString& data = event->data();
if (!checkDataSize(event, 14)) return;
peer->cleanPlayerProfiles();
// can we add the player ?
if (!allowJoinedPlayersWaiting() &&
(m_state.load() != WAITING_FOR_START_GAME ||
m_game_setup->isGrandPrixStarted()))
{
NetworkString *message = getNetworkString(2);
message->setSynchronous(true);
message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_BUSY);
// send only to the peer that made the request and disconnect it now
peer->sendPacket(message, true/*reliable*/, false/*encrypted*/);
peer->reset();
delete message;
Log::verbose("ServerLobby", "Player refused: selection started");
return;
}
// Check server version
int version = data.getUInt32();
if (version < stk_config->m_min_server_version ||
version > stk_config->m_max_server_version)
{
NetworkString *message = getNetworkString(2);
message->setSynchronous(true);
message->addUInt8(LE_CONNECTION_REFUSED)
.addUInt8(RR_INCOMPATIBLE_DATA);
peer->sendPacket(message, true/*reliable*/, false/*encrypted*/);
peer->reset();
delete message;
Log::verbose("ServerLobby", "Player refused: wrong server version");
return;
}
std::string user_version;
data.decodeString(&user_version);
event->getPeer()->setUserVersion(user_version);
unsigned list_caps = data.getUInt16();
std::set<std::string> caps;
for (unsigned i = 0; i < list_caps; i++)
{
std::string cap;
data.decodeString(&cap);
caps.insert(cap);
}
event->getPeer()->setClientCapabilities(caps);
std::set<std::string> client_karts, client_tracks;
const unsigned kart_num = data.getUInt16();
const unsigned track_num = data.getUInt16();
const unsigned kart_num = ns.getUInt16();
const unsigned track_num = ns.getUInt16();
for (unsigned i = 0; i < kart_num; i++)
{
std::string kart;
data.decodeString(&kart);
ns.decodeString(&kart);
client_karts.insert(kart);
}
for (unsigned i = 0; i < track_num; i++)
{
std::string track;
data.decodeString(&track);
ns.decodeString(&track);
client_tracks.insert(track);
}
@ -3032,12 +2983,70 @@ void ServerLobby::connectionRequested(Event* event)
peer->reset();
delete message;
Log::verbose("ServerLobby", "Player has incompatible karts / tracks.");
return;
return false;
}
// Save available karts and tracks from clients in STKPeer so if this peer
// disconnects later in lobby it won't affect current players
peer->setAvailableKartsTracks(client_karts, client_tracks);
return true;
} // handleAssets
//-----------------------------------------------------------------------------
void ServerLobby::connectionRequested(Event* event)
{
std::shared_ptr<STKPeer> peer = event->getPeerSP();
NetworkString& data = event->data();
if (!checkDataSize(event, 14)) return;
peer->cleanPlayerProfiles();
// can we add the player ?
if (!allowJoinedPlayersWaiting() &&
(m_state.load() != WAITING_FOR_START_GAME ||
m_game_setup->isGrandPrixStarted()))
{
NetworkString *message = getNetworkString(2);
message->setSynchronous(true);
message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_BUSY);
// send only to the peer that made the request and disconnect it now
peer->sendPacket(message, true/*reliable*/, false/*encrypted*/);
peer->reset();
delete message;
Log::verbose("ServerLobby", "Player refused: selection started");
return;
}
// Check server version
int version = data.getUInt32();
if (version < stk_config->m_min_server_version ||
version > stk_config->m_max_server_version)
{
NetworkString *message = getNetworkString(2);
message->setSynchronous(true);
message->addUInt8(LE_CONNECTION_REFUSED)
.addUInt8(RR_INCOMPATIBLE_DATA);
peer->sendPacket(message, true/*reliable*/, false/*encrypted*/);
peer->reset();
delete message;
Log::verbose("ServerLobby", "Player refused: wrong server version");
return;
}
std::string user_version;
data.decodeString(&user_version);
event->getPeer()->setUserVersion(user_version);
unsigned list_caps = data.getUInt16();
std::set<std::string> caps;
for (unsigned i = 0; i < list_caps; i++)
{
std::string cap;
data.decodeString(&cap);
caps.insert(cap);
}
event->getPeer()->setClientCapabilities(caps);
if (!handleAssets(data, event->getPeer()))
return;
unsigned player_count = data.getUInt8();
uint32_t online_id = 0;

View File

@ -316,6 +316,7 @@ private:
std::vector<std::shared_ptr<NetworkPlayerProfile> >& players) const;
std::vector<std::shared_ptr<NetworkPlayerProfile> > getLivePlayers() const;
void setPlayerKarts(const NetworkString& ns, STKPeer* peer) const;
bool handleAssets(const NetworkString& ns, STKPeer* peer) const;
void liveJoinRequest(Event* event);
void rejectLiveJoin(STKPeer* peer, BackLobbyReason blr);
bool canLiveJoinNow() const;

View File

@ -28,6 +28,7 @@
#include "guiengine/widgets.hpp"
#include "input/input_manager.hpp"
#include "io/file_manager.hpp"
#include "network/protocols/client_lobby.hpp"
#include "online/request_manager.hpp"
#include "online/xml_request.hpp"
#include "race/grand_prix_manager.hpp"
@ -81,7 +82,12 @@ AddonsLoading::~AddonsLoading()
{
// Select the last selected item in the addons_screen, so that
// users can keep on installing from the last selected item.
AddonsScreen::getInstance()->setLastSelected();
// This dialog can be called in network lobby screen atm for live addon
// install
AddonsScreen* as = dynamic_cast<AddonsScreen*>(
GUIEngine::getCurrentScreen());
if (as)
as->setLastSelected();
} // AddonsLoading
// ----------------------------------------------------------------------------
@ -210,7 +216,25 @@ bool AddonsLoading::onEscapePressed()
} // onEscapePressed
// ----------------------------------------------------------------------------
void AddonsLoading::tryInstall()
{
#ifndef SERVER_ONLY
// Only display the progress bar etc. if we are not uninstalling an addon.
if (!m_addon.isInstalled() || m_addon.needsUpdate())
{
m_progress->setValue(0);
m_progress->setVisible(true);
// Change the 'back' button into a 'cancel' button.
m_back_button->setLabel(_("Cancel"));
GUIEngine::RibbonWidget* actions_ribbon =
getWidget<GUIEngine::RibbonWidget>("actions");
actions_ribbon->setVisible(false);
startDownload();
}
#endif
} // tryInstall
// ----------------------------------------------------------------------------
GUIEngine::EventPropagation AddonsLoading::processEvent(const std::string& event_source)
{
#ifndef SERVER_ONLY
@ -230,19 +254,7 @@ GUIEngine::EventPropagation AddonsLoading::processEvent(const std::string& event
}
else if(selection == "install")
{
// Only display the progress bar etc. if we are
// not uninstalling an addon.
if(!m_addon.isInstalled() || m_addon.needsUpdate())
{
m_progress->setValue(0);
m_progress->setVisible(true);
// Change the 'back' button into a 'cancel' button.
m_back_button->setLabel(_("Cancel"));
actions_ribbon->setVisible(false);
startDownload();
}
tryInstall();
return GUIEngine::EVENT_BLOCK;
}
else if (selection == "uninstall")
@ -395,7 +407,10 @@ void AddonsLoading::doInstall()
{
// The list of the addon screen needs to be updated to correctly
// display the newly (un)installed addon.
AddonsScreen::getInstance()->loadList();
AddonsScreen* as = dynamic_cast<AddonsScreen*>(
GUIEngine::getCurrentScreen());
if (as)
as->loadList();
dismiss();
}
@ -405,6 +420,9 @@ void AddonsLoading::doInstall()
delete grand_prix_manager;
grand_prix_manager = new GrandPrixManager();
grand_prix_manager->checkConsistency();
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->updateAssetsToServer();
#endif
} // doInstall
@ -439,7 +457,10 @@ void AddonsLoading::doUninstall()
{
// The list of the addon screen needs to be updated to correctly
// display the newly (un)installed addon.
AddonsScreen::getInstance()->loadList();
AddonsScreen* as = dynamic_cast<AddonsScreen*>(
GUIEngine::getCurrentScreen());
if (as)
as->loadList();
dismiss();
}
// Update the replay file list to use latest track pointer
@ -447,5 +468,8 @@ void AddonsLoading::doUninstall()
delete grand_prix_manager;
grand_prix_manager = new GrandPrixManager();
grand_prix_manager->checkConsistency();
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->updateAssetsToServer();
#endif
} // doUninstall

View File

@ -71,6 +71,7 @@ public:
* */
void onUpdate(float delta) OVERRIDE;
void voteClicked();
void tryInstall();
virtual bool onEscapePressed() OVERRIDE;
}; // AddonsLoading

View File

@ -24,10 +24,12 @@
#include "io/file_manager.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
#include "network/protocols/client_lobby.hpp"
#include "online/http_request.hpp"
#include "race/grand_prix_manager.hpp"
#include "replay/replay_play.hpp"
#include "states_screens/addons_screen.hpp"
#include "states_screens/dialogs/addons_loading.hpp"
#include "states_screens/dialogs/message_dialog.hpp"
#include "states_screens/state_manager.hpp"
#include "tracks/track_manager.hpp"
@ -239,8 +241,7 @@ void AddonsPack::doInstall()
{
if (r == ".." || r == ".")
continue;
std::string addon_id = "addon_";
addon_id += r;
std::string addon_id = Addon::createAddonId(r);
// We assume the addons pack the user downloaded use the latest
// revision from the stk-addons (if exists)
if (file_manager->fileExists(tmp_extract + r + "/stkskin.xml"))
@ -301,8 +302,44 @@ void AddonsPack::doInstall()
GUIEngine::getCurrentScreen());
if (as)
as->loadList();
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->updateAssetsToServer();
delete request;
}
} // doInstall
// ----------------------------------------------------------------------------
void AddonsPack::install(const std::string& name)
{
// Only install addon live in menu
if (StateManager::get()->getGameState() != GUIEngine::MENU &&
!ModalDialog::isADialogActive())
return;
Addon* addon = addons_manager->getAddon(Addon::createAddonId(name));
if (addon)
{
AddonsLoading* al = new AddonsLoading(addon->getId());
al->tryInstall();
}
else
{
// Assume it's addon pack url
new AddonsPack(name);
}
} // install
// ----------------------------------------------------------------------------
void AddonsPack::uninstall(const std::string& name)
{
// Only uninstall addon live in menu
if (StateManager::get()->getGameState() != GUIEngine::MENU)
return;
Addon* addon = addons_manager->getAddon(Addon::createAddonId(name));
if (addon && addons_manager->uninstall(*addon))
{
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->updateAssetsToServer();
}
} // uninstall
#endif

View File

@ -38,15 +38,15 @@ private:
/** A pointer to the download request, which gives access
* to the progress of a download. */
AddonsPackRequest* m_download_request;
public:
AddonsPack(const std::string& url);
public:
virtual GUIEngine::EventPropagation processEvent(const std::string& event_source) OVERRIDE;
virtual void beforeAddingWidgets() OVERRIDE;
virtual void init() OVERRIDE;
void onUpdate(float delta) OVERRIDE;
virtual bool onEscapePressed() OVERRIDE;
static void install(const std::string& name);
static void uninstall(const std::string& name);
}; // DownloadAssets
#endif

View File

@ -337,7 +337,18 @@ void RacePausedDialog::beforeAddingWidgets()
bool RacePausedDialog::onEnterPressed(const irr::core::stringw& text)
{
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->sendChat(text);
{
if (!text.empty())
{
if (text[0] == L'/' && text.size() > 1)
{
std::string cmd = StringUtils::wideToUtf8(text);
cl->handleClientCommand(cmd.erase(0, 1));
}
else
cl->sendChat(text);
}
}
m_self_destroy = true;
return true;
} // onEnterPressed

View File

@ -568,7 +568,18 @@ void NetworkingLobby::updatePlayerPings()
bool NetworkingLobby::onEnterPressed(const irr::core::stringw& text)
{
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->sendChat(text);
{
if (!text.empty())
{
if (text[0] == L'/' && text.size() > 1)
{
std::string cmd = StringUtils::wideToUtf8(text);
cl->handleClientCommand(cmd.erase(0, 1));
}
else
cl->sendChat(text);
}
}
return true;
} // onEnterPressed
@ -601,8 +612,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name,
} // click on a user
else if (name == m_send_button->m_properties[PROP_ID])
{
if (auto cl = LobbyProtocol::get<ClientLobby>())
cl->sendChat(m_chat_box->getText());
onEnterPressed(m_chat_box->getText());
m_chat_box->setText("");
} // send chat message
else if (name == m_emoji_button->m_properties[PROP_ID] &&