diff --git a/Content.Server/Chat/SuicideSystem.cs b/Content.Server/Chat/SuicideSystem.cs index 106d6363fc..d1646f7e64 100644 --- a/Content.Server/Chat/SuicideSystem.cs +++ b/Content.Server/Chat/SuicideSystem.cs @@ -33,7 +33,7 @@ namespace Content.Server.Chat if (!TryComp(victim, out var mobState) || _mobState.IsDead(victim, mobState)) return false; - _adminLogger.Add(LogType.Suicide, $"{EntityManager.ToPrettyString(victim):player} is committing suicide"); + _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(victim):player} is attempting to suicide"); var suicideEvent = new SuicideEvent(victim); @@ -41,9 +41,12 @@ namespace Content.Server.Chat if (SuicideAttemptBlocked(victim, suicideEvent)) return false; + bool environmentSuicide = false; // If you are critical, you wouldn't be able to use your surroundings to suicide, so you do the default suicide if (!_mobState.IsCritical(victim, mobState)) - EnvironmentSuicideHandler(victim, suicideEvent); + { + environmentSuicide = EnvironmentSuicideHandler(victim, suicideEvent); + } if (suicideEvent.AttemptBlocked) return false; @@ -51,6 +54,7 @@ namespace Content.Server.Chat DefaultSuicideHandler(victim, suicideEvent); ApplyDeath(victim, suicideEvent.Kind!.Value); + _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(victim):player} suicided{(environmentSuicide ? " (environment)" : "")}"); return true; } @@ -87,7 +91,7 @@ namespace Content.Server.Chat /// /// Raise event to attempt to use held item, or surrounding entities to attempt to commit suicide /// - private void EnvironmentSuicideHandler(EntityUid victim, SuicideEvent suicideEvent) + private bool EnvironmentSuicideHandler(EntityUid victim, SuicideEvent suicideEvent) { var itemQuery = GetEntityQuery(); @@ -98,7 +102,7 @@ namespace Content.Server.Chat RaiseLocalEvent(item, suicideEvent, false); if (suicideEvent.Handled) - return; + return true; } // Suicide by nearby entity (ex: Microwave) @@ -111,8 +115,10 @@ namespace Content.Server.Chat RaiseLocalEvent(entity, suicideEvent, false); if (suicideEvent.Handled) - break; + return true; } + + return false; } private void ApplyDeath(EntityUid target, SuicideKind kind) diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs index 9c58c96cb9..c070585296 100644 --- a/Content.Server/GameTicking/GameTicker.GamePreset.cs +++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs @@ -7,6 +7,7 @@ using Content.Server.MobState; using Content.Shared.CCVar; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; +using Content.Shared.Database; using Content.Shared.MobState.Components; using Robust.Server.Player; @@ -147,8 +148,13 @@ namespace Content.Server.GameTicking } } - public bool OnGhostAttempt(Mind.Mind mind, bool canReturnGlobal) + public bool OnGhostAttempt(Mind.Mind mind, bool canReturnGlobal, bool viaCommand = false) { + var playerEntity = mind.CurrentEntity; + + if (playerEntity != null && viaCommand) + _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} is attempting to ghost via command"); + var handleEv = new GhostAttemptHandleEvent(mind, canReturnGlobal); RaiseLocalEvent(handleEv); @@ -160,12 +166,11 @@ namespace Content.Server.GameTicking { if (mind.Session != null) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts - _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"), true); + _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"), + true); return false; } - var playerEntity = mind.CurrentEntity; - var entities = IoCManager.Resolve(); if (entities.HasComponent(playerEntity)) return false; @@ -220,6 +225,9 @@ namespace Content.Server.GameTicking ghostComponent.TimeOfDeath = mind.TimeOfDeath!.Value; } + if (playerEntity != null) + _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} ghosted{(!canReturn ? " (non-returnable)" : "")}"); + _ghosts.SetCanReturnToBody(ghostComponent, canReturn); if (canReturn) diff --git a/Content.Server/Ghost/Ghost.cs b/Content.Server/Ghost/Ghost.cs index 5fcbbb86bb..989ab99159 100644 --- a/Content.Server/Ghost/Ghost.cs +++ b/Content.Server/Ghost/Ghost.cs @@ -29,7 +29,7 @@ namespace Content.Server.Ghost return; } - if (!EntitySystem.Get().OnGhostAttempt(mind, true)) + if (!EntitySystem.Get().OnGhostAttempt(mind, true, viaCommand:true)) { shell?.WriteLine("You can't ghost right now."); return; diff --git a/Content.Server/Mind/Mind.cs b/Content.Server/Mind/Mind.cs index c0ae7e8b5b..770a6f0311 100644 --- a/Content.Server/Mind/Mind.cs +++ b/Content.Server/Mind/Mind.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; +using Content.Server.Administration.Logs; using Content.Server.GameTicking; using Content.Server.Ghost.Components; using Content.Server.Mind.Components; @@ -7,6 +8,7 @@ using Content.Server.MobState; using Content.Server.Objectives; using Content.Server.Players; using Content.Server.Roles; +using Content.Shared.Database; using Content.Shared.MobState.Components; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -32,6 +34,7 @@ namespace Content.Server.Mind private readonly MindSystem _mindSystem = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; private readonly ISet _roles = new HashSet(); @@ -177,6 +180,21 @@ namespace Content.Server.Mind } } + /// + /// A string to represent the mind for logging + /// + private string MindOwnerLoggingString + { + get + { + if (OwnedEntity != null) + return _entityManager.ToPrettyString(OwnedEntity.Value); + if (UserId != null) + return UserId.Value.ToString(); + return "(originally " + OriginalOwnerUserId + ")"; + } + } + /// /// Gives this mind a new role. /// @@ -200,6 +218,8 @@ namespace Content.Server.Mind { _entityManager.EventBus.RaiseLocalEvent(OwnedEntity.Value, message, true); } + _adminLogger.Add(LogType.Mind, LogImpact.Low, + $"'{role.Name}' added to mind of {MindOwnerLoggingString}"); return role; } @@ -226,6 +246,8 @@ namespace Content.Server.Mind { _entityManager.EventBus.RaiseLocalEvent(OwnedEntity.Value, message, true); } + _adminLogger.Add(LogType.Mind, LogImpact.Low, + $"'{role.Name}' removed from mind of {MindOwnerLoggingString}"); } public bool HasRole() where T : Role @@ -250,6 +272,11 @@ namespace Content.Server.Mind var objective = objectivePrototype.GetObjective(this); if (_objectives.Contains(objective)) return false; + + foreach (var condition in objective.Conditions) + _adminLogger.Add(LogType.Mind, LogImpact.Low, $"'{condition.Title}' added to mind of {MindOwnerLoggingString}"); + + _objectives.Add(objective); return true; } @@ -263,6 +290,10 @@ namespace Content.Server.Mind if (_objectives.Count >= index) return false; var objective = _objectives[index]; + + foreach (var condition in objective.Conditions) + _adminLogger.Add(LogType.Mind, LogImpact.Low, $"'{condition.Title}' removed from the mind of {MindOwnerLoggingString}"); + _objectives.Remove(objective); return true; } @@ -404,8 +435,13 @@ namespace Content.Server.Mind /// public void UnVisit() { + var currentEntity = Session?.AttachedEntity; Session?.AttachToEntity(OwnedEntity); RemoveVisitingEntity(); + + if (Session != null && OwnedEntity != null && currentEntity != OwnedEntity) + _adminLogger.Add(LogType.Mind, LogImpact.Low, + $"{Session.Name} returned to {_entityManager.ToPrettyString(OwnedEntity.Value)}"); } /// diff --git a/Content.Shared.Database/LogType.cs b/Content.Shared.Database/LogType.cs index 9cac618bb1..d6230e5678 100644 --- a/Content.Shared.Database/LogType.cs +++ b/Content.Shared.Database/LogType.cs @@ -44,7 +44,7 @@ public enum LogType Ingestion = 53, // voluntary MeleeHit = 41, HitScanHit = 42, - Suicide = 43, + Mind = 43, // Suicides, ghosting, repossession, objectives, etc. Explosion = 44, Radiation = 45, // Unused Barotrauma = 46,