Allow always spectating with /spectate [0 or 1]
This commit is contained in:
parent
b122572a0c
commit
53bf93f2df
@ -1174,6 +1174,8 @@ void ClientLobby::backToLobby(Event *event)
|
||||
|
||||
NetworkString &data = event->data();
|
||||
core::stringw msg;
|
||||
MessageQueue::MessageType mt = MessageQueue::MT_ERROR;
|
||||
|
||||
switch ((BackLobbyReason)data.getUInt8()) // the second byte
|
||||
{
|
||||
case BLR_NO_GAME_FOR_LIVE_JOIN:
|
||||
@ -1192,15 +1194,23 @@ void ClientLobby::backToLobby(Event *event)
|
||||
// I18N: Error message shown when all players will go back to lobby
|
||||
// when server owner quited the game
|
||||
if (!STKHost::get()->isClientServer())
|
||||
msg = _("Server owner quit the game");
|
||||
msg = _("Server owner quit the game.");
|
||||
break;
|
||||
case BLR_SPECTATING_NEXT_GAME:
|
||||
// I18N: Status shown to player when he will be spectating the next game
|
||||
msg = _("You will be spectating the next game.");
|
||||
mt = MessageQueue::MT_GENERIC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!msg.empty())
|
||||
{
|
||||
SFXManager::get()->quickSound("anvil");
|
||||
MessageQueue::add(MessageQueue::MT_ERROR, msg);
|
||||
if (mt == MessageQueue::MT_GENERIC)
|
||||
SFXManager::get()->quickSound("plopp");
|
||||
else
|
||||
SFXManager::get()->quickSound("anvil");
|
||||
MessageQueue::add(mt, msg);
|
||||
}
|
||||
} // backToLobby
|
||||
|
||||
|
@ -99,7 +99,8 @@ public:
|
||||
BLR_NO_GAME_FOR_LIVE_JOIN = 1,
|
||||
BLR_NO_PLACE_FOR_LIVE_JOIN = 2,
|
||||
BLR_ONE_PLAYER_IN_RANKED_MATCH = 3,
|
||||
BLR_SERVER_ONWER_QUITED_THE_GAME = 4
|
||||
BLR_SERVER_ONWER_QUITED_THE_GAME = 4,
|
||||
BLR_SPECTATING_NEXT_GAME = 5
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -1547,7 +1547,9 @@ void ServerLobby::asynchronousUpdate()
|
||||
m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch();
|
||||
ItemManager::updateRandomSeed(m_item_seed);
|
||||
m_game_setup->setRace(winner_vote);
|
||||
auto players = STKHost::get()->getPlayersForNewGame();
|
||||
bool has_always_on_spectators = false;
|
||||
auto players = STKHost::get()
|
||||
->getPlayersForNewGame(&has_always_on_spectators);
|
||||
auto ai_instance = m_ai_peer.lock();
|
||||
if (supportsAI())
|
||||
{
|
||||
@ -1617,6 +1619,10 @@ void ServerLobby::asynchronousUpdate()
|
||||
resetPeersReady();
|
||||
m_state = LOAD_WORLD;
|
||||
sendMessageToPeers(load_world_message);
|
||||
// updatePlayerList so the in lobby players (if any) can see always
|
||||
// spectators join the game
|
||||
if (has_always_on_spectators)
|
||||
updatePlayerList();
|
||||
delete load_world_message;
|
||||
}
|
||||
break;
|
||||
@ -2427,13 +2433,37 @@ void ServerLobby::startSelection(const Event *event)
|
||||
// Remove karts / tracks from server that are not supported on all clients
|
||||
std::set<std::string> karts_erase, tracks_erase;
|
||||
auto peers = STKHost::get()->getPeers();
|
||||
std::set<STKPeer*> always_spectate_peers;
|
||||
bool has_peer_plays_game = false;
|
||||
for (auto peer : peers)
|
||||
{
|
||||
if (!peer->isValidated() || peer->isWaitingForGame())
|
||||
continue;
|
||||
peer->eraseServerKarts(m_available_kts.first, karts_erase);
|
||||
peer->eraseServerTracks(m_available_kts.second, tracks_erase);
|
||||
if (peer->alwaysSpectate())
|
||||
always_spectate_peers.insert(peer.get());
|
||||
else if (!peer->isAIPeer())
|
||||
has_peer_plays_game = true;
|
||||
}
|
||||
|
||||
// Disable always spectate peers if no players join the game
|
||||
if (!has_peer_plays_game)
|
||||
{
|
||||
for (STKPeer* peer : always_spectate_peers)
|
||||
peer->setAlwaysSpectate(false);
|
||||
always_spectate_peers.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We make those always spectate peer waiting for game so it won't
|
||||
// be able to vote, this will be reset in STKHost::getPlayersForNewGame
|
||||
// This will also allow a correct number of in game players for max
|
||||
// arena players handling
|
||||
for (STKPeer* peer : always_spectate_peers)
|
||||
peer->setWaitingForGame(true);
|
||||
}
|
||||
|
||||
for (const std::string& kart_erase : karts_erase)
|
||||
{
|
||||
m_available_kts.first.erase(kart_erase);
|
||||
@ -2589,6 +2619,19 @@ void ServerLobby::startSelection(const Event *event)
|
||||
delete ns;
|
||||
|
||||
m_state = SELECTING;
|
||||
if (!always_spectate_peers.empty())
|
||||
{
|
||||
NetworkString* back_lobby = getNetworkString(2);
|
||||
back_lobby->setSynchronous(true);
|
||||
back_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_SPECTATING_NEXT_GAME);
|
||||
STKHost::get()->sendPacketToAllPeersWith(
|
||||
[always_spectate_peers](STKPeer* peer) {
|
||||
return always_spectate_peers.find(peer) !=
|
||||
always_spectate_peers.end(); }, back_lobby, /*reliable*/true);
|
||||
delete back_lobby;
|
||||
updatePlayerList();
|
||||
}
|
||||
|
||||
if (!allowJoinedPlayersWaiting())
|
||||
{
|
||||
// Drop all pending players and keys if doesn't allow joinning-waiting
|
||||
@ -3721,6 +3764,12 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
|
||||
!update_when_reset_server;
|
||||
|
||||
auto all_profiles = STKHost::get()->getAllPlayerProfiles();
|
||||
size_t all_profiles_size = all_profiles.size();
|
||||
for (auto& profile : all_profiles)
|
||||
{
|
||||
if (profile->getPeer()->alwaysSpectate())
|
||||
all_profiles_size--;
|
||||
}
|
||||
// N - 1 AI
|
||||
auto ai_instance = m_ai_peer.lock();
|
||||
if (supportsAI())
|
||||
@ -3731,12 +3780,12 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
|
||||
if (m_state.load() == WAITING_FOR_START_GAME ||
|
||||
update_when_reset_server)
|
||||
{
|
||||
if (all_profiles.size() > ai_profiles.size())
|
||||
if (all_profiles_size > ai_profiles.size())
|
||||
ai_profiles.clear();
|
||||
else if (!all_profiles.empty())
|
||||
else if (all_profiles_size != 0)
|
||||
{
|
||||
ai_profiles.resize(
|
||||
ai_profiles.size() - all_profiles.size() + 1);
|
||||
ai_profiles.size() - all_profiles_size + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -3774,7 +3823,9 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
|
||||
uint8_t boolean_combine = 0;
|
||||
if (p && p->isWaitingForGame())
|
||||
boolean_combine |= 1;
|
||||
if (p && p->isSpectator())
|
||||
if (p && (p->isSpectator() ||
|
||||
((m_state.load() == WAITING_FOR_START_GAME ||
|
||||
update_when_reset_server) && p->alwaysSpectate())))
|
||||
boolean_combine |= (1 << 1);
|
||||
if (p && m_server_owner_id.load() == p->getHostId())
|
||||
boolean_combine |= (1 << 2);
|
||||
@ -4413,7 +4464,8 @@ void ServerLobby::configPeersStartTime()
|
||||
for (auto p : m_peers_ready)
|
||||
{
|
||||
auto peer = p.first.lock();
|
||||
if (!peer)
|
||||
// Spectators don't send input so we don't need to delay for them
|
||||
if (!peer || peer->alwaysSpectate())
|
||||
continue;
|
||||
if (peer->getAveragePing() > max_ping_from_peers)
|
||||
{
|
||||
@ -5267,7 +5319,7 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::handleServerCommand(Event* event,
|
||||
std::shared_ptr<STKPeer> peer) const
|
||||
std::shared_ptr<STKPeer> peer)
|
||||
{
|
||||
NetworkString& data = event->data();
|
||||
std::string language;
|
||||
@ -5277,7 +5329,54 @@ void ServerLobby::handleServerCommand(Event* event,
|
||||
auto argv = StringUtils::split(cmd, ' ');
|
||||
if (argv.size() == 0)
|
||||
return;
|
||||
if (argv[0] == "listserveraddon")
|
||||
if (argv[0] == "spectate")
|
||||
{
|
||||
if (m_game_setup->isGrandPrix() || !ServerConfig::m_live_players)
|
||||
{
|
||||
NetworkString* chat = getNetworkString();
|
||||
chat->addUInt8(LE_CHAT);
|
||||
chat->setSynchronous(true);
|
||||
std::string msg = "Server doesn't support spectate";
|
||||
chat->encodeString16(StringUtils::utf8ToWide(msg));
|
||||
peer->sendPacket(chat, true/*reliable*/);
|
||||
delete chat;
|
||||
return;
|
||||
}
|
||||
|
||||
if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1") ||
|
||||
m_state.load() != WAITING_FOR_START_GAME)
|
||||
{
|
||||
NetworkString* chat = getNetworkString();
|
||||
chat->addUInt8(LE_CHAT);
|
||||
chat->setSynchronous(true);
|
||||
std::string msg = "Usage: spectate [0 or 1], before game started";
|
||||
chat->encodeString16(StringUtils::utf8ToWide(msg));
|
||||
peer->sendPacket(chat, true/*reliable*/);
|
||||
delete chat;
|
||||
return;
|
||||
}
|
||||
|
||||
if (argv[1] == "1")
|
||||
{
|
||||
if (m_process_type == PT_CHILD &&
|
||||
peer->getHostId() == m_client_server_host_id.load())
|
||||
{
|
||||
NetworkString* chat = getNetworkString();
|
||||
chat->addUInt8(LE_CHAT);
|
||||
chat->setSynchronous(true);
|
||||
std::string msg = "Graphical client server cannot spectate";
|
||||
chat->encodeString16(StringUtils::utf8ToWide(msg));
|
||||
peer->sendPacket(chat, true/*reliable*/);
|
||||
delete chat;
|
||||
return;
|
||||
}
|
||||
peer->setAlwaysSpectate(true);
|
||||
}
|
||||
else
|
||||
peer->setAlwaysSpectate(false);
|
||||
updatePlayerList();
|
||||
}
|
||||
else if (argv[0] == "listserveraddon")
|
||||
{
|
||||
NetworkString* chat = getNetworkString();
|
||||
chat->addUInt8(LE_CHAT);
|
||||
|
@ -338,7 +338,7 @@ private:
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> > getLivePlayers() const;
|
||||
void setPlayerKarts(const NetworkString& ns, STKPeer* peer) const;
|
||||
bool handleAssets(const NetworkString& ns, STKPeer* peer);
|
||||
void handleServerCommand(Event* event, std::shared_ptr<STKPeer> peer) const;
|
||||
void handleServerCommand(Event* event, std::shared_ptr<STKPeer> peer);
|
||||
void liveJoinRequest(Event* event);
|
||||
void rejectLiveJoin(STKPeer* peer, BackLobbyReason blr);
|
||||
bool canLiveJoinNow() const;
|
||||
|
@ -1528,13 +1528,21 @@ std::pair<int, int> STKHost::getAllPlayersTeamInfo() const
|
||||
/** Get the players for starting a new game.
|
||||
* \return A vector containing pointers on the players profiles. */
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> >
|
||||
STKHost::getPlayersForNewGame() const
|
||||
STKHost::getPlayersForNewGame(bool* has_always_on_spectators) const
|
||||
{
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> > players;
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
for (auto& p : m_peers)
|
||||
{
|
||||
auto& stk_peer = p.second;
|
||||
// Handle always spectate for peer
|
||||
if (has_always_on_spectators && stk_peer->alwaysSpectate())
|
||||
{
|
||||
*has_always_on_spectators = true;
|
||||
stk_peer->setWaitingForGame(false);
|
||||
stk_peer->setSpectator(true);
|
||||
continue;
|
||||
}
|
||||
if (stk_peer->isWaitingForGame())
|
||||
continue;
|
||||
if (ServerConfig::m_ai_handling && stk_peer->isAIPeer())
|
||||
|
@ -386,7 +386,7 @@ public:
|
||||
uint32_t getTotalPlayers() const { return m_total_players.load(); }
|
||||
// ------------------------------------------------------------------------
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> >
|
||||
getPlayersForNewGame() const;
|
||||
getPlayersForNewGame(bool* has_always_on_spectators = NULL) const;
|
||||
// ------------------------------------------------------------------------
|
||||
void replaceNetwork(Network* new_network)
|
||||
{
|
||||
|
@ -44,6 +44,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id)
|
||||
m_host_id = host_id;
|
||||
m_connected_time = StkTime::getMonoTimeMs();
|
||||
m_validated.store(false);
|
||||
m_always_spectate.store(false);
|
||||
m_average_ping.store(0);
|
||||
m_packet_loss.store(0);
|
||||
m_waiting_for_game.store(true);
|
||||
|
@ -85,6 +85,8 @@ protected:
|
||||
|
||||
std::atomic_bool m_warned_for_high_ping;
|
||||
|
||||
std::atomic_bool m_always_spectate;
|
||||
|
||||
/** Host id of this peer. */
|
||||
uint32_t m_host_id;
|
||||
|
||||
@ -289,6 +291,11 @@ public:
|
||||
int getConsecutiveMessages() const { return m_consecutive_messages; }
|
||||
// ------------------------------------------------------------------------
|
||||
const SocketAddress& getAddress() const { return *m_socket_address.get(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void setAlwaysSpectate(bool val) { m_always_spectate.store(val); }
|
||||
// ------------------------------------------------------------------------
|
||||
bool alwaysSpectate() const { return m_always_spectate.load(); }
|
||||
|
||||
}; // STKPeer
|
||||
|
||||
#endif // STK_PEER_HPP
|
||||
|
Loading…
Reference in New Issue
Block a user