diff --git a/Content.Client/Voting/UI/VoteCallMenu.xaml.cs b/Content.Client/Voting/UI/VoteCallMenu.xaml.cs index eae01c6aff..e62baba7e2 100644 --- a/Content.Client/Voting/UI/VoteCallMenu.xaml.cs +++ b/Content.Client/Voting/UI/VoteCallMenu.xaml.cs @@ -12,6 +12,7 @@ using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; +using Robust.Shared.Network; using Robust.Shared.Timing; namespace Content.Client.Voting.UI @@ -22,6 +23,7 @@ namespace Content.Client.Voting.UI [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IVoteManager _voteManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IClientNetManager _netManager = default!; public static readonly (string name, StandardVoteType type, (string name, string id)[]? secondaries)[] AvailableVoteTypes = @@ -54,6 +56,8 @@ namespace Content.Client.Voting.UI { base.Opened(); + _netManager.ClientSendMessage(new MsgVoteMenu()); + _voteManager.CanCallVoteChanged += CanCallVoteChanged; } diff --git a/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs b/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs index 28f259d996..8ca122a5b2 100644 --- a/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs +++ b/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs @@ -4,6 +4,7 @@ using Content.Server.GameTicking.Presets; using Content.Server.Maps; using Content.Server.RoundEnd; using Content.Shared.CCVar; +using Content.Shared.Database; using Content.Shared.Voting; using Robust.Server.Player; using Robust.Shared.Configuration; @@ -22,6 +23,11 @@ namespace Content.Server.Voting.Managers public void CreateStandardVote(IPlayerSession? initiator, StandardVoteType voteType) { + if (initiator != null) + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"{initiator} initiated a {voteType.ToString()} vote"); + else + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Initiated a {voteType.ToString()} vote"); + switch (voteType) { case StandardVoteType.Restart: @@ -75,12 +81,14 @@ namespace Content.Server.Voting.Managers var ratioRequired = _cfg.GetCVar(CCVars.VoteRestartRequiredRatio); if (total > 0 && votesYes / (float) total >= ratioRequired) { + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote succeeded: {votesYes}/{votesNo}"); _chatManager.DispatchServerAnnouncement(Loc.GetString("ui-vote-restart-succeeded")); var roundEnd = _entityManager.EntitySysManager.GetEntitySystem(); roundEnd.EndRound(); } else { + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Restart vote failed: {votesYes}/{votesNo}"); _chatManager.DispatchServerAnnouncement( Loc.GetString("ui-vote-restart-failed", ("ratio", ratioRequired))); } @@ -142,6 +150,7 @@ namespace Content.Server.Voting.Managers _chatManager.DispatchServerAnnouncement( Loc.GetString("ui-vote-gamemode-win", ("winner", Loc.GetString(presets[picked])))); } + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Preset vote finished: {picked}"); var ticker = _entityManager.EntitySysManager.GetEntitySystem(); ticker.SetGamePreset(picked); }; @@ -188,6 +197,7 @@ namespace Content.Server.Voting.Managers Loc.GetString("ui-vote-map-win", ("winner", maps[picked]))); } + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Map vote finished: {picked.MapName}"); var ticker = _entityManager.EntitySysManager.GetEntitySystem(); if (ticker.RunLevel == GameRunLevel.PreRoundLobby) { diff --git a/Content.Server/Voting/Managers/VoteManager.cs b/Content.Server/Voting/Managers/VoteManager.cs index a2733d6ba4..94933a0f16 100644 --- a/Content.Server/Voting/Managers/VoteManager.cs +++ b/Content.Server/Voting/Managers/VoteManager.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Administration; +using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; using Content.Server.Afk; using Content.Server.Chat.Managers; @@ -10,6 +11,7 @@ using Content.Server.GameTicking; using Content.Server.Maps; using Content.Shared.Administration; using Content.Shared.CCVar; +using Content.Shared.Database; using Content.Shared.Voting; using Robust.Server.Player; using Robust.Shared.Configuration; @@ -35,6 +37,7 @@ namespace Content.Server.Voting.Managers [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IGameMapManager _gameMapManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; private int _nextVoteId = 1; @@ -50,6 +53,7 @@ namespace Content.Server.Voting.Managers { _netManager.RegisterNetMessage(); _netManager.RegisterNetMessage(); + _netManager.RegisterNetMessage(ReceiveVoteMenu); _playerManager.PlayerStatusChanged += PlayerManagerOnPlayerStatusChanged; _adminMgr.OnPermsChanged += AdminPermsChanged; @@ -66,6 +70,14 @@ namespace Content.Server.Voting.Managers } } + private void ReceiveVoteMenu(MsgVoteMenu message) + { + var sender = message.MsgChannel; + var session = _playerManager.GetSessionByChannel(sender); + + _adminLogger.Add(LogType.Vote, LogImpact.Low, $"{session} opened vote menu"); + } + private void AdminPermsChanged(AdminPermsChangedEventArgs obj) { DirtyCanCallVote(obj.Player); diff --git a/Content.Server/Voting/VoteCommands.cs b/Content.Server/Voting/VoteCommands.cs index 6a77644bb4..cb296a7d58 100644 --- a/Content.Server/Voting/VoteCommands.cs +++ b/Content.Server/Voting/VoteCommands.cs @@ -1,8 +1,10 @@ using System.Linq; using Content.Server.Administration; +using Content.Server.Administration.Logs; using Content.Server.Chat.Managers; using Content.Server.Voting.Managers; using Content.Shared.Administration; +using Content.Shared.Database; using Content.Shared.Voting; using Robust.Server.Player; using Robust.Shared.Console; @@ -12,6 +14,8 @@ namespace Content.Server.Voting [AnyCommand] public sealed class CreateVoteCommand : IConsoleCommand { + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + public string Command => "createvote"; public string Description => Loc.GetString("cmd-createvote-desc"); public string Help => Loc.GetString("cmd-createvote-help"); @@ -34,6 +38,7 @@ namespace Content.Server.Voting if (shell.Player != null && !mgr.CanCallVote((IPlayerSession) shell.Player, type)) { + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"{shell.Player} failed to start {type.ToString()} vote"); shell.WriteError(Loc.GetString("cmd-createvote-cannot-call-vote-now")); return; } @@ -56,6 +61,8 @@ namespace Content.Server.Voting [AdminCommand(AdminFlags.Admin)] public sealed class CreateCustomCommand : IConsoleCommand { + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + private const int MaxArgCount = 10; public string Command => "customvote"; @@ -87,6 +94,11 @@ namespace Content.Server.Voting options.SetInitiatorOrServer((IPlayerSession?) shell.Player); + if (shell.Player != null) + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"{shell.Player} initiated a custom vote: {options.Title} - {string.Join("; ", options.Options.Select(x => x.text))}"); + else + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Initiated a custom vote: {options.Title} - {string.Join("; ", options.Options.Select(x => x.text))}"); + var vote = mgr.CreateVote(options); vote.OnFinished += (_, eventArgs) => @@ -95,10 +107,12 @@ namespace Content.Server.Voting if (eventArgs.Winner == null) { var ties = string.Join(", ", eventArgs.Winners.Select(c => args[(int) c])); + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Custom vote {options.Title} finished as tie: {ties}"); chatMgr.DispatchServerAnnouncement(Loc.GetString("cmd-customvote-on-finished-tie",("ties", ties))); } else { + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Custom vote {options.Title} finished: {args[(int) eventArgs.Winner]}"); chatMgr.DispatchServerAnnouncement(Loc.GetString("cmd-customvote-on-finished-win",("winner", args[(int) eventArgs.Winner]))); } }; @@ -198,6 +212,8 @@ namespace Content.Server.Voting [AdminCommand(AdminFlags.Admin)] public sealed class CancelVoteCommand : IConsoleCommand { + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + public string Command => "cancelvote"; public string Description => Loc.GetString("cmd-cancelvote-desc"); public string Help => Loc.GetString("cmd-cancelvote-help"); @@ -218,6 +234,10 @@ namespace Content.Server.Voting return; } + if (shell.Player != null) + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"{shell.Player} canceled vote: {vote.Title}"); + else + _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Canceled vote: {vote.Title}"); vote.Cancel(); } diff --git a/Content.Shared.Database/LogType.cs b/Content.Shared.Database/LogType.cs index 073002f06b..652ef0d7b5 100644 --- a/Content.Shared.Database/LogType.cs +++ b/Content.Shared.Database/LogType.cs @@ -85,4 +85,5 @@ public enum LogType WireHacking = 80, Teleport = 81, EntityDelete = 82, + Vote = 83, } diff --git a/Content.Shared/Voting/MsgVoteMenu.cs b/Content.Shared/Voting/MsgVoteMenu.cs new file mode 100644 index 0000000000..d94b326156 --- /dev/null +++ b/Content.Shared/Voting/MsgVoteMenu.cs @@ -0,0 +1,20 @@ +using Lidgren.Network; +using Robust.Shared.Network; +using Robust.Shared.Serialization; + +namespace Content.Shared.Voting; + +public sealed class MsgVoteMenu : NetMessage +{ + public override MsgGroups MsgGroup => MsgGroups.Command; + + public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) + { + } + + public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) + { + } + + public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered; +}