Restart votes check player count and ghost levels (#23453)

* Restarts have max player count

* Now counts ingame ghosts to determine if restart can be called

* consistant cvar name

* Added a player count with state conditional
This commit is contained in:
Repo
2024-01-19 20:10:05 +13:00
committed by GitHub
parent c35b9964c7
commit 7bf62f1d19
3 changed files with 119 additions and 60 deletions

View File

@@ -5,8 +5,10 @@ using Content.Server.Maps;
using Content.Server.RoundEnd; using Content.Server.RoundEnd;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Ghost;
using Content.Shared.Voting; using Content.Shared.Voting;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Random; using Robust.Shared.Random;
@@ -49,73 +51,117 @@ namespace Content.Server.Voting.Managers
private void CreateRestartVote(ICommonSession? initiator) private void CreateRestartVote(ICommonSession? initiator)
{ {
var alone = _playerManager.PlayerCount == 1 && initiator != null;
var options = new VoteOptions
{
Title = Loc.GetString("ui-vote-restart-title"),
Options =
{
(Loc.GetString("ui-vote-restart-yes"), "yes"),
(Loc.GetString("ui-vote-restart-no"), "no"),
(Loc.GetString("ui-vote-restart-abstain"), "abstain")
},
Duration = alone
? TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.VoteTimerAlone))
: TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.VoteTimerRestart)),
InitiatorTimeout = TimeSpan.FromMinutes(5)
};
if (alone) var playerVoteMaximum = _cfg.GetCVar(CCVars.VoteRestartMaxPlayers);
options.InitiatorTimeout = TimeSpan.FromSeconds(10); var totalPlayers = _playerManager.Sessions.Count(session => session.Status != SessionStatus.Disconnected);
WirePresetVoteInitiator(options, initiator);
var vote = CreateVote(options);
vote.OnFinished += (_, _) =>
{
var votesYes = vote.VotesPerOption["yes"];
var votesNo = vote.VotesPerOption["no"];
var total = votesYes + votesNo;
var ratioRequired = _cfg.GetCVar(CCVars.VoteRestartRequiredRatio);
if (total > 0 && votesYes / (float) total >= ratioRequired)
{
// Check if an admin is online, and ignore the passed vote if the cvar is enabled
if (_cfg.GetCVar(CCVars.VoteRestartNotAllowedWhenAdminOnline) && _adminMgr.ActiveAdmins.Count() != 0)
{
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote attempted to pass, but an admin was online. {votesYes}/{votesNo}");
}
else // If the cvar is disabled or there's no admins on, proceed as normal
{
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote succeeded: {votesYes}/{votesNo}");
_chatManager.DispatchServerAnnouncement(Loc.GetString("ui-vote-restart-succeeded"));
var roundEnd = _entityManager.EntitySysManager.GetEntitySystem<RoundEndSystem>();
roundEnd.EndRound();
}
}
else
{
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote failed: {votesYes}/{votesNo}");
_chatManager.DispatchServerAnnouncement(
Loc.GetString("ui-vote-restart-failed", ("ratio", ratioRequired)));
}
};
if (initiator != null)
{
// Cast yes vote if created the vote yourself.
vote.CastVote(initiator, 0);
}
var ghostVotePercentageRequirement = _cfg.GetCVar(CCVars.VoteRestartGhostPercentage);
var ghostCount = 0;
foreach (var player in _playerManager.Sessions) foreach (var player in _playerManager.Sessions)
{ {
if (player != initiator) _playerManager.UpdateState(player);
if (player.Status != SessionStatus.Disconnected && _entityManager.HasComponent<GhostComponent>(player.AttachedEntity))
{ {
// Everybody else defaults to an abstain vote to say they don't mind. ghostCount++;
vote.CastVote(player, 2);
} }
} }
var ghostPercentage = 0.0;
if (totalPlayers > 0)
{
ghostPercentage = ((double)ghostCount / totalPlayers) * 100;
}
var roundedGhostPercentage = (int)Math.Round(ghostPercentage);
if (totalPlayers <= playerVoteMaximum || roundedGhostPercentage >= ghostVotePercentageRequirement)
{
StartVote(initiator);
}
else
{
NotifyNotEnoughGhostPlayers(ghostVotePercentageRequirement, roundedGhostPercentage);
}
}
private void StartVote(ICommonSession? initiator)
{
var alone = _playerManager.PlayerCount == 1 && initiator != null;
var options = new VoteOptions
{
Title = Loc.GetString("ui-vote-restart-title"),
Options =
{
(Loc.GetString("ui-vote-restart-yes"), "yes"),
(Loc.GetString("ui-vote-restart-no"), "no"),
(Loc.GetString("ui-vote-restart-abstain"), "abstain")
},
Duration = alone
? TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.VoteTimerAlone))
: TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.VoteTimerRestart)),
InitiatorTimeout = TimeSpan.FromMinutes(5)
};
if (alone)
options.InitiatorTimeout = TimeSpan.FromSeconds(10);
WirePresetVoteInitiator(options, initiator);
var vote = CreateVote(options);
vote.OnFinished += (_, _) =>
{
var votesYes = vote.VotesPerOption["yes"];
var votesNo = vote.VotesPerOption["no"];
var total = votesYes + votesNo;
var ratioRequired = _cfg.GetCVar(CCVars.VoteRestartRequiredRatio);
if (total > 0 && votesYes / (float) total >= ratioRequired)
{
// Check if an admin is online, and ignore the passed vote if the cvar is enabled
if (_cfg.GetCVar(CCVars.VoteRestartNotAllowedWhenAdminOnline) && _adminMgr.ActiveAdmins.Count() != 0)
{
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote attempted to pass, but an admin was online. {votesYes}/{votesNo}");
}
else // If the cvar is disabled or there's no admins on, proceed as normal
{
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote succeeded: {votesYes}/{votesNo}");
_chatManager.DispatchServerAnnouncement(Loc.GetString("ui-vote-restart-succeeded"));
var roundEnd = _entityManager.EntitySysManager.GetEntitySystem<RoundEndSystem>();
roundEnd.EndRound();
}
}
else
{
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote failed: {votesYes}/{votesNo}");
_chatManager.DispatchServerAnnouncement(
Loc.GetString("ui-vote-restart-failed", ("ratio", ratioRequired)));
}
};
if (initiator != null)
{
// Cast yes vote if created the vote yourself.
vote.CastVote(initiator, 0);
}
foreach (var player in _playerManager.Sessions)
{
if (player != initiator)
{
// Everybody else defaults to an abstain vote to say they don't mind.
vote.CastVote(player, 2);
}
}
}
private void NotifyNotEnoughGhostPlayers(int ghostPercentageRequirement, int roundedGhostPercentage)
{
// Logic to notify that there are not enough ghost players to start a vote
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote failed: Current Ghost player percentage:{roundedGhostPercentage.ToString()}% does not meet {ghostPercentageRequirement.ToString()}%");
_chatManager.DispatchServerAnnouncement(
Loc.GetString("ui-vote-restart-fail-not-enough-ghost-players", ("ghostPlayerRequirement", ghostPercentageRequirement)));
} }
private void CreatePresetVote(ICommonSession? initiator) private void CreatePresetVote(ICommonSession? initiator)

View File

@@ -1256,6 +1256,18 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> VoteRestartEnabled = public static readonly CVarDef<bool> VoteRestartEnabled =
CVarDef.Create("vote.restart_enabled", true, CVar.SERVERONLY); CVarDef.Create("vote.restart_enabled", true, CVar.SERVERONLY);
/// <summary>
/// Config for when the restart vote should be allowed to be called regardless with less than this amount of players.
/// </summary>
public static readonly CVarDef<int> VoteRestartMaxPlayers =
CVarDef.Create("vote.restart_max_players", 20, CVar.SERVERONLY);
/// <summary>
/// Config for when the restart vote should be allowed to be called based on percentage of ghosts.
///
public static readonly CVarDef<int> VoteRestartGhostPercentage =
CVarDef.Create("vote.restart_ghost_percentage", 75, CVar.SERVERONLY);
/// <summary> /// <summary>
/// See vote.enabled, but specific to preset votes /// See vote.enabled, but specific to preset votes
/// </summary> /// </summary>

View File

@@ -6,6 +6,7 @@ ui-vote-initiator-server = The server
ui-vote-restart-title = Restart round ui-vote-restart-title = Restart round
ui-vote-restart-succeeded = Restart vote succeeded. ui-vote-restart-succeeded = Restart vote succeeded.
ui-vote-restart-failed = Restart vote failed (need { TOSTRING($ratio, "P0") }). ui-vote-restart-failed = Restart vote failed (need { TOSTRING($ratio, "P0") }).
ui-vote-restart-fail-not-enough-ghost-players = Restart vote failed: A minimum of { $ghostPlayerRequirement }% ghost players is required to initiate a restart vote. Currently, there are not enough ghost players.
ui-vote-restart-yes = Yes ui-vote-restart-yes = Yes
ui-vote-restart-no = No ui-vote-restart-no = No
ui-vote-restart-abstain = Abstain ui-vote-restart-abstain = Abstain