using Content.Shared.Administration.Logs; using Content.Shared.CCVar; using Content.Shared.DragDrop; using Content.Shared.GameTicking; using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Mobs.Systems; using Robust.Shared.Configuration; using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Timing; namespace Content.Shared.Bed.Cryostorage; /// /// This handles /// public abstract class SharedCryostorageSystem : EntitySystem { [Dependency] protected readonly ISharedAdminLogManager AdminLog = default!; [Dependency] private readonly IConfigurationManager _configuration = default!; [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] protected readonly SharedMindSystem Mind = default!; [Dependency] private readonly MobStateSystem _mobState = default!; protected EntityUid? PausedMap { get; private set; } protected bool CryoSleepRejoiningEnabled; /// public override void Initialize() { SubscribeLocalEvent(OnInsertedContainer); SubscribeLocalEvent(OnRemovedContainer); SubscribeLocalEvent(OnInsertAttempt); SubscribeLocalEvent(OnShutdownContainer); SubscribeLocalEvent(OnCanDropTarget); SubscribeLocalEvent(OnRemovedContained); SubscribeLocalEvent(OnShutdownContained); SubscribeLocalEvent(OnRoundRestart); Subs.CVar(_configuration, CCVars.GameCryoSleepRejoining, OnCvarChanged, true); } private void OnCvarChanged(bool value) { CryoSleepRejoiningEnabled = value; } protected virtual void OnInsertedContainer(Entity ent, ref EntInsertedIntoContainerMessage args) { var (_, comp) = ent; if (args.Container.ID != comp.ContainerId) return; _appearance.SetData(ent, CryostorageVisuals.Full, true); if (!Timing.IsFirstTimePredicted) return; var containedComp = EnsureComp(args.Entity); var delay = Mind.TryGetMind(args.Entity, out _, out _) ? comp.GracePeriod : comp.NoMindGracePeriod; containedComp.GracePeriodEndTime = Timing.CurTime + delay; containedComp.Cryostorage = ent; Dirty(args.Entity, containedComp); } private void OnRemovedContainer(Entity ent, ref EntRemovedFromContainerMessage args) { var (_, comp) = ent; if (args.Container.ID != comp.ContainerId) return; _appearance.SetData(ent, CryostorageVisuals.Full, args.Container.ContainedEntities.Count > 0); } private void OnInsertAttempt(Entity ent, ref ContainerIsInsertingAttemptEvent args) { var (_, comp) = ent; if (args.Container.ID != comp.ContainerId) return; if (_mobState.IsIncapacitated(args.EntityUid)) { args.Cancel(); return; } if (!HasComp(args.EntityUid) || !TryComp(args.EntityUid, out var mindContainer)) { args.Cancel(); return; } if (Mind.TryGetMind(args.EntityUid, out _, out var mindComp, mindContainer) && (mindComp.PreventSuicide || mindComp.PreventGhosting)) { args.Cancel(); } } private void OnShutdownContainer(Entity ent, ref ComponentShutdown args) { var comp = ent.Comp; foreach (var stored in comp.StoredPlayers) { if (TryComp(stored, out var containedComponent)) { containedComponent.Cryostorage = null; Dirty(stored, containedComponent); } } comp.StoredPlayers.Clear(); Dirty(ent, comp); } private void OnCanDropTarget(Entity ent, ref CanDropTargetEvent args) { if (args.Dragged == args.User) return; if (!Mind.TryGetMind(args.Dragged, out _, out var mindComp) || mindComp.Session?.AttachedEntity != args.Dragged) return; args.CanDrop = false; args.Handled = true; } private void OnRemovedContained(Entity ent, ref EntGotRemovedFromContainerMessage args) { var (uid, comp) = ent; if (!IsInPausedMap(uid)) RemCompDeferred(ent, comp); } private void OnShutdownContained(Entity ent, ref ComponentShutdown args) { var comp = ent.Comp; CompOrNull(comp.Cryostorage)?.StoredPlayers.Remove(ent); ent.Comp.Cryostorage = null; Dirty(ent, comp); } private void OnRoundRestart(RoundRestartCleanupEvent _) { DeletePausedMap(); } private void DeletePausedMap() { if (PausedMap == null || !Exists(PausedMap)) return; EntityManager.DeleteEntity(PausedMap.Value); PausedMap = null; } protected void EnsurePausedMap() { if (PausedMap != null && Exists(PausedMap)) return; var map = _mapManager.CreateMap(); _mapManager.SetMapPaused(map, true); PausedMap = _mapManager.GetMapEntityId(map); } public bool IsInPausedMap(Entity entity) { var (_, comp) = entity; comp ??= Transform(entity); return comp.MapUid != null && comp.MapUid == PausedMap; } }