From 7948f466dbe07e0de4a58e469b9bafe6f239a597 Mon Sep 17 00:00:00 2001 From: Tornado Tech <54727692+Tornado-Technology@users.noreply.github.com> Date: Tue, 31 Dec 2024 07:04:05 +1000 Subject: [PATCH] Cryosleep portals (#209) * Create AutoCryoSleep * Fixed AutoCryoSleep * Added delay * Fixed is't alive mobs * Added tags * Update Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepSystem.cs Co-authored-by: FN <37689533+FireNameFN@users.noreply.github.com> --------- Co-authored-by: FN <37689533+FireNameFN@users.noreply.github.com> --- .../AutoCryoSleep/AutoCryoSleepComponent.cs | 18 +++ .../AutoCryoSleep/AutoCryoSleepSystem.cs | 141 ++++++++++++++++++ .../AutoCryoSleepableComponent.cs | 9 ++ Content.Shared/_CorvaxNext/NextVars.cs | 13 ++ 4 files changed, 181 insertions(+) create mode 100644 Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepComponent.cs create mode 100644 Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepSystem.cs create mode 100644 Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepableComponent.cs diff --git a/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepComponent.cs b/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepComponent.cs new file mode 100644 index 00000000000..96378cd2b02 --- /dev/null +++ b/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepComponent.cs @@ -0,0 +1,18 @@ +/* + * Author: TornadoTech + * License: AGPL + */ + +using Robust.Shared.Prototypes; + +namespace Content.Server._CorvaxNext.AutoCryoSleep; + +[RegisterComponent] +public sealed partial class AutoCryoSleepComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite)] + public TimeSpan Disconnected; + + [ViewVariables(VVAccess.ReadWrite)] + public EntProtoId? EffectId = "JetpackEffect"; +} diff --git a/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepSystem.cs b/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepSystem.cs new file mode 100644 index 00000000000..5e8de83349f --- /dev/null +++ b/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepSystem.cs @@ -0,0 +1,141 @@ +/* + * Author: TornadoTech + * License: AGPL + */ + +using System.Diagnostics.CodeAnalysis; +using Content.Shared._CorvaxNext.NextVars; +using Content.Shared.Bed.Cryostorage; +using Content.Shared.Mobs.Systems; +using Content.Shared.Station.Components; +using Robust.Server.Containers; +using Robust.Shared.Configuration; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Server._CorvaxNext.AutoCryoSleep; + +public sealed class AutoCryoSleepSystem : EntitySystem +{ + [Dependency] private readonly IConfigurationManager _config = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ContainerSystem _container = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + + private bool _enabled; + private TimeSpan _disconnectedTime; + private TimeSpan _updateTime; + + private TimeSpan _nextUpdate = TimeSpan.Zero; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + + Subs.CVar(_config, NextVars.AutoCryoSleepEnabled, value => _enabled = value, true); + Subs.CVar(_config, NextVars.AutoCryoSleepTime, value => _disconnectedTime = TimeSpan.FromSeconds(value), true); + Subs.CVar(_config, NextVars.AutoCryoSleepUpdateTime, value => _updateTime = TimeSpan.FromSeconds(value), true); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (!_enabled) + return; + + if (_timing.CurTime < _nextUpdate) + return; + + _nextUpdate = _timing.CurTime + _updateTime; + + var disconnectedQuery = EntityQueryEnumerator(); + while (disconnectedQuery.MoveNext(out var uid, out var component)) + { + if (_timing.CurTime - component.Disconnected < _disconnectedTime) + continue; + + if (!_mobState.IsAlive(uid)) + { + RemCompDeferred(uid); + continue; + } + + TryCryoSleep(uid, component.EffectId); + } + } + + private void OnPlayerAttached(Entity ent, ref PlayerAttachedEvent args) + { + if (!_enabled) + return; + + RemCompDeferred(ent); + } + + private void OnPlayerDetached(Entity ent, ref PlayerDetachedEvent args) + { + if (!_enabled) + return; + + var comp = EnsureComp(ent); + comp.Disconnected = _timing.CurTime; + } + + private void TryCryoSleep(EntityUid targetUid, EntProtoId? effectId = null) + { + if (HasComp(targetUid)) + return; + + if (!TryGetStation(targetUid, out var stationUid)) + return; + + foreach (var cryostorageEntity in EnumerateCryostorageInSameStation(stationUid.Value)) + { + if (!_container.TryGetContainer(cryostorageEntity, cryostorageEntity.Comp.ContainerId, out var container)) + continue; + + // We need only empty cryo sleeps + if (!_container.CanInsert(targetUid, container)) + continue; + + if (effectId is not null) + Spawn(effectId, Transform(targetUid).Coordinates); + + _container.Insert(targetUid, container); + + RemCompDeferred(targetUid); + } + } + + private IEnumerable> EnumerateCryostorageInSameStation(EntityUid stationUid) + { + var query = AllEntityQuery(); + while (query.MoveNext(out var entityUid, out var cryostorageComponent)) + { + if (!TryGetStation(entityUid, out var cryoStationUid)) + continue; + + if (stationUid != cryoStationUid) + continue; + + yield return (entityUid, cryostorageComponent); + } + } + + private bool TryGetStation(EntityUid entityUid, [NotNullWhen(true)] out EntityUid? stationUid) + { + stationUid = null; + var gridUid = Transform(entityUid).GridUid; + + if (!TryComp(gridUid, out var stationMemberComponent)) + return false; + + stationUid = stationMemberComponent.Station; + return true; + } +} diff --git a/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepableComponent.cs b/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepableComponent.cs new file mode 100644 index 00000000000..c8ff3d02167 --- /dev/null +++ b/Content.Server/_CorvaxNext/AutoCryoSleep/AutoCryoSleepableComponent.cs @@ -0,0 +1,9 @@ +/* + * Author: TornadoTech + * License: AGPL + */ + +namespace Content.Server._CorvaxNext.AutoCryoSleep; + +[RegisterComponent] +public sealed partial class AutoCryoSleepableComponent : Component; diff --git a/Content.Shared/_CorvaxNext/NextVars.cs b/Content.Shared/_CorvaxNext/NextVars.cs index 2effecae306..7d451d2a182 100644 --- a/Content.Shared/_CorvaxNext/NextVars.cs +++ b/Content.Shared/_CorvaxNext/NextVars.cs @@ -9,6 +9,19 @@ namespace Content.Shared._CorvaxNext.NextVars; // ReSharper disable once InconsistentNaming public sealed class NextVars { + /** + * Auto cryo sleep + */ + + public static readonly CVarDef AutoCryoSleepEnabled = + CVarDef.Create("auto_cryo_sleep.enabled", true, CVar.SERVER); + + public static readonly CVarDef AutoCryoSleepTime = + CVarDef.Create("auto_cryo_sleep.time", 500, CVar.SERVER); + + public static readonly CVarDef AutoCryoSleepUpdateTime = + CVarDef.Create("auto_cryo_sleep.update_time", 120, CVar.SERVER); + /// /// Offer item. ///