Predict sleeping action (#37414)

* Predict sleeping action

* reviews
This commit is contained in:
metalgearsloth
2025-05-15 22:52:24 +10:00
committed by GitHub
parent 7ec37451d0
commit c042669eae
6 changed files with 86 additions and 38 deletions

View File

@@ -0,0 +1,8 @@
using Content.Shared.Bed;
namespace Content.Client.Bed;
public sealed class BedSystem : SharedBedSystem
{
}

View File

@@ -1,9 +1,9 @@
using Content.Server.Actions;
using Content.Server.Bed.Components;
using Content.Server.Body.Systems;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Bed;
using Content.Shared.Bed.Components;
using Content.Shared.Bed.Sleep;
using Content.Shared.Body.Components;
using Content.Shared.Buckle.Components;
@@ -11,49 +11,30 @@ using Content.Shared.Damage;
using Content.Shared.Emag.Systems;
using Content.Shared.Mobs.Systems;
using Content.Shared.Power;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Bed
{
public sealed class BedSystem : EntitySystem
public sealed class BedSystem : SharedBedSystem
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly ActionsSystem _actionsSystem = default!;
[Dependency] private readonly EmagSystem _emag = default!;
[Dependency] private readonly SleepingSystem _sleepingSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private EntityQuery<SleepingComponent> _sleepingQuery;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HealOnBuckleComponent, StrappedEvent>(OnStrapped);
SubscribeLocalEvent<HealOnBuckleComponent, UnstrappedEvent>(OnUnstrapped);
_sleepingQuery = GetEntityQuery<SleepingComponent>();
SubscribeLocalEvent<StasisBedComponent, StrappedEvent>(OnStasisStrapped);
SubscribeLocalEvent<StasisBedComponent, UnstrappedEvent>(OnStasisUnstrapped);
SubscribeLocalEvent<StasisBedComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<StasisBedComponent, GotEmaggedEvent>(OnEmagged);
}
private void OnStrapped(Entity<HealOnBuckleComponent> bed, ref StrappedEvent args)
{
EnsureComp<HealOnBuckleHealingComponent>(bed);
bed.Comp.NextHealTime = _timing.CurTime + TimeSpan.FromSeconds(bed.Comp.HealTime);
_actionsSystem.AddAction(args.Buckle, ref bed.Comp.SleepAction, SleepingSystem.SleepActionId, bed);
// Single action entity, cannot strap multiple entities to the same bed.
DebugTools.AssertEqual(args.Strap.Comp.BuckledEntities.Count, 1);
}
private void OnUnstrapped(Entity<HealOnBuckleComponent> bed, ref UnstrappedEvent args)
{
_actionsSystem.RemoveAction(args.Buckle, bed.Comp.SleepAction);
_sleepingSystem.TryWaking(args.Buckle.Owner);
RemComp<HealOnBuckleHealingComponent>(bed);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
@@ -61,7 +42,7 @@ namespace Content.Server.Bed
var query = EntityQueryEnumerator<HealOnBuckleHealingComponent, HealOnBuckleComponent, StrapComponent>();
while (query.MoveNext(out var uid, out _, out var bedComponent, out var strapComponent))
{
if (_timing.CurTime < bedComponent.NextHealTime)
if (Timing.CurTime < bedComponent.NextHealTime)
continue;
bedComponent.NextHealTime += TimeSpan.FromSeconds(bedComponent.HealTime);
@@ -76,7 +57,7 @@ namespace Content.Server.Bed
var damage = bedComponent.Damage;
if (HasComp<SleepingComponent>(healedEntity))
if (_sleepingQuery.HasComp(healedEntity))
damage *= bedComponent.SleepMultiplier;
_damageableSystem.TryChangeDamage(healedEntity, damage, true, origin: uid);

View File

@@ -1,7 +0,0 @@
namespace Content.Server.Bed.Components
{
// TODO rename this component
[RegisterComponent]
public sealed partial class HealOnBuckleHealingComponent : Component
{}
}

View File

@@ -1,8 +1,10 @@
using Content.Shared.Damage;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Bed.Components
namespace Content.Shared.Bed.Components
{
[RegisterComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause, AutoGenerateComponentState]
public sealed partial class HealOnBuckleComponent : Component
{
/// <summary>
@@ -23,8 +25,16 @@ namespace Content.Server.Bed.Components
[DataField]
public float SleepMultiplier = 3f;
/// <summary>
/// Next time that <see cref="Damage"/> will be applied.
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField, AutoNetworkedField]
public TimeSpan NextHealTime = TimeSpan.Zero; //Next heal
[DataField] public EntityUid? SleepAction;
/// <summary>
/// Action for the attached entity to be able to sleep.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? SleepAction;
}
}

View File

@@ -0,0 +1,7 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Bed.Components;
// TODO rename this component
[RegisterComponent, NetworkedComponent]
public sealed partial class HealOnBuckleHealingComponent : Component;

View File

@@ -0,0 +1,49 @@
using Content.Shared.Actions;
using Content.Shared.Bed.Components;
using Content.Shared.Bed.Sleep;
using Content.Shared.Buckle.Components;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Shared.Bed;
public abstract class SharedBedSystem : EntitySystem
{
[Dependency] protected readonly IGameTiming Timing = default!;
[Dependency] private readonly ActionContainerSystem _actConts = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly SleepingSystem _sleepingSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HealOnBuckleComponent, MapInitEvent>(OnHealMapInit);
SubscribeLocalEvent<HealOnBuckleComponent, StrappedEvent>(OnStrapped);
SubscribeLocalEvent<HealOnBuckleComponent, UnstrappedEvent>(OnUnstrapped);
}
private void OnHealMapInit(Entity<HealOnBuckleComponent> ent, ref MapInitEvent args)
{
_actConts.EnsureAction(ent.Owner, ref ent.Comp.SleepAction, SleepingSystem.SleepActionId);
Dirty(ent);
}
private void OnStrapped(Entity<HealOnBuckleComponent> bed, ref StrappedEvent args)
{
EnsureComp<HealOnBuckleHealingComponent>(bed);
bed.Comp.NextHealTime = Timing.CurTime + TimeSpan.FromSeconds(bed.Comp.HealTime);
_actionsSystem.AddAction(args.Buckle, ref bed.Comp.SleepAction, SleepingSystem.SleepActionId, bed);
Dirty(bed);
// Single action entity, cannot strap multiple entities to the same bed.
DebugTools.AssertEqual(args.Strap.Comp.BuckledEntities.Count, 1);
}
private void OnUnstrapped(Entity<HealOnBuckleComponent> bed, ref UnstrappedEvent args)
{
_actionsSystem.RemoveAction(args.Buckle, bed.Comp.SleepAction);
_sleepingSystem.TryWaking(args.Buckle.Owner);
RemComp<HealOnBuckleHealingComponent>(bed);
}
}