diff --git a/Content.Server/Administration/Logs/AdminLogManager.Json.cs b/Content.Server/Administration/Logs/AdminLogManager.Json.cs index 0d14b004b6..d5d073ff44 100644 --- a/Content.Server/Administration/Logs/AdminLogManager.Json.cs +++ b/Content.Server/Administration/Logs/AdminLogManager.Json.cs @@ -24,6 +24,7 @@ public sealed partial class AdminLogManager foreach (var converter in _reflection.FindTypesWithAttribute()) { var instance = _typeFactory.CreateInstance(converter); + (instance as IAdminLogConverter)?.Init(_dependencies); _jsonOptions.Converters.Add(instance); } diff --git a/Content.Server/Administration/Logs/AdminLogManager.cs b/Content.Server/Administration/Logs/AdminLogManager.cs index 4b40f77232..8959fb1a13 100644 --- a/Content.Server/Administration/Logs/AdminLogManager.cs +++ b/Content.Server/Administration/Logs/AdminLogManager.cs @@ -24,6 +24,7 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IDynamicTypeFactory _typeFactory = default!; [Dependency] private readonly IReflectionManager _reflection = default!; + [Dependency] private readonly IDependencyCollection _dependencies = default!; public const string SawmillId = "admin.logs"; diff --git a/Content.Server/Administration/Logs/Converters/AdminLogConverter.cs b/Content.Server/Administration/Logs/Converters/AdminLogConverter.cs index 0f2ce3983a..7eaab9ba28 100644 --- a/Content.Server/Administration/Logs/Converters/AdminLogConverter.cs +++ b/Content.Server/Administration/Logs/Converters/AdminLogConverter.cs @@ -3,8 +3,17 @@ using System.Text.Json.Serialization; namespace Content.Server.Administration.Logs.Converters; -public abstract class AdminLogConverter : JsonConverter +public interface IAdminLogConverter { + void Init(IDependencyCollection dependencies); +} + +public abstract class AdminLogConverter : JsonConverter, IAdminLogConverter +{ + public virtual void Init(IDependencyCollection dependencies) + { + } + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotSupportedException(); diff --git a/Content.Server/Administration/Logs/Converters/AdminLogConverterAttribute.cs b/Content.Server/Administration/Logs/Converters/AdminLogConverterAttribute.cs index 78418adb67..ac1be307a5 100644 --- a/Content.Server/Administration/Logs/Converters/AdminLogConverterAttribute.cs +++ b/Content.Server/Administration/Logs/Converters/AdminLogConverterAttribute.cs @@ -4,6 +4,7 @@ namespace Content.Server.Administration.Logs.Converters; [AttributeUsage(AttributeTargets.Class)] [BaseTypeRequired(typeof(AdminLogConverter<>))] +[MeansImplicitUse] public sealed class AdminLogConverterAttribute : Attribute { } diff --git a/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs b/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs index 04b36a1834..2fc1a2b627 100644 --- a/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs +++ b/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs @@ -6,7 +6,14 @@ namespace Content.Server.Administration.Logs.Converters; [AdminLogConverter] public sealed class EntityUidConverter : AdminLogConverter { - [Dependency] private readonly IEntityManager _entities = default!; + // System.Text.Json actually keeps hold of your JsonSerializerOption instances in a cache on .NET 7. + // Use a weak reference to avoid holding server instances live too long in integration tests. + private WeakReference _entityManager = default!; + + public override void Init(IDependencyCollection dependencies) + { + _entityManager = new WeakReference(dependencies.Resolve()); + } public static void Write(Utf8JsonWriter writer, EntityUid value, JsonSerializerOptions options, IEntityManager entities) { @@ -29,6 +36,9 @@ public sealed class EntityUidConverter : AdminLogConverter public override void Write(Utf8JsonWriter writer, EntityUid value, JsonSerializerOptions options) { - Write(writer, value, options, _entities); + if (!_entityManager.TryGetTarget(out var entityManager)) + throw new InvalidOperationException("EntityManager got garbage collected!"); + + Write(writer, value, options, entityManager); } } diff --git a/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs b/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs index ab5a0dcff9..0605c2db2a 100644 --- a/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs +++ b/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs @@ -6,13 +6,23 @@ namespace Content.Server.Administration.Logs.Converters; [AdminLogConverter] public sealed class PlayerSessionConverter : AdminLogConverter { + // System.Text.Json actually keeps hold of your JsonSerializerOption instances in a cache on .NET 7. + // Use a weak reference to avoid holding server instances live too long in integration tests. + private WeakReference _entityManager = default!; + + public override void Init(IDependencyCollection dependencies) + { + _entityManager = new WeakReference(dependencies.Resolve()); + } + public override void Write(Utf8JsonWriter writer, SerializablePlayer value, JsonSerializerOptions options) { writer.WriteStartObject(); if (value.Player.AttachedEntity is {Valid: true} playerEntity) { - var entityManager = IoCManager.Resolve(); + if (!_entityManager.TryGetTarget(out var entityManager)) + throw new InvalidOperationException("EntityManager got garbage collected!"); writer.WriteNumber("id", (int) value.Player.AttachedEntity); writer.WriteString("name", entityManager.GetComponent(playerEntity).EntityName);