Fix door saving/loading (#6506)
This commit is contained in:
@@ -44,16 +44,21 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
SubscribeLocalEvent<DoorComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<DoorComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnInit(EntityUid uid, DoorComponent door, ComponentInit args)
|
protected override void SetCollidable(EntityUid uid, bool collidable,
|
||||||
|
DoorComponent? door = null,
|
||||||
|
PhysicsComponent? physics = null,
|
||||||
|
OccluderComponent? occluder = null)
|
||||||
{
|
{
|
||||||
base.OnInit(uid, door, args);
|
if (!Resolve(uid, ref door))
|
||||||
|
return;
|
||||||
|
|
||||||
if (door.State == DoorState.Open
|
if (door.ChangeAirtight && TryComp(uid, out AirtightComponent? airtight))
|
||||||
&& door.ChangeAirtight
|
_airtightSystem.SetAirblocked(airtight, collidable);
|
||||||
&& TryComp(uid, out AirtightComponent? airtight))
|
|
||||||
{
|
// Pathfinding / AI stuff.
|
||||||
_airtightSystem.SetAirblocked(airtight, false);
|
RaiseLocalEvent(new AccessReaderChangeMessage(uid, collidable));
|
||||||
}
|
|
||||||
|
base.SetCollidable(uid, collidable, door, physics, occluder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO AUDIO PREDICT Figure out a better way to handle sound and prediction. For now, this works well enough?
|
// TODO AUDIO PREDICT Figure out a better way to handle sound and prediction. For now, this works well enough?
|
||||||
@@ -250,39 +255,6 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
TryOpen(uid, door, otherUid);
|
TryOpen(uid, door, otherUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnPartialOpen(EntityUid uid, DoorComponent? door = null, PhysicsComponent? physics = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref door, ref physics))
|
|
||||||
return;
|
|
||||||
|
|
||||||
base.OnPartialOpen(uid, door, physics);
|
|
||||||
|
|
||||||
if (door.ChangeAirtight && TryComp(uid, out AirtightComponent? airtight))
|
|
||||||
{
|
|
||||||
_airtightSystem.SetAirblocked(airtight, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Path-finding. Has nothing directly to do with access readers.
|
|
||||||
RaiseLocalEvent(new AccessReaderChangeMessage(uid, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnPartialClose(EntityUid uid, DoorComponent? door = null, PhysicsComponent? physics = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref door, ref physics))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!base.OnPartialClose(uid, door, physics))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// update airtight, if we did not crush something.
|
|
||||||
if (door.ChangeAirtight && door.CurrentlyCrushing.Count == 0 && TryComp(uid, out AirtightComponent? airtight))
|
|
||||||
_airtightSystem.SetAirblocked(airtight, true);
|
|
||||||
|
|
||||||
// Path-finding. Has nothing directly to do with access readers.
|
|
||||||
RaiseLocalEvent(new AccessReaderChangeMessage(uid, true));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, DoorComponent door, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, DoorComponent door, MapInitEvent args)
|
||||||
{
|
{
|
||||||
// Ensure that the construction component is aware of the board container.
|
// Ensure that the construction component is aware of the board container.
|
||||||
|
|||||||
@@ -1,23 +1,19 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using Content.Shared.Tools;
|
using Content.Shared.Tools;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.Timing;
|
||||||
using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth;
|
using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth;
|
||||||
|
|
||||||
namespace Content.Shared.Doors.Components;
|
namespace Content.Shared.Doors.Components;
|
||||||
|
|
||||||
[NetworkedComponent]
|
[NetworkedComponent]
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed class DoorComponent : Component
|
public sealed class DoorComponent : Component, ISerializationHooks
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current state of the door -- whether it is open, closed, opening, or closing.
|
/// The current state of the door -- whether it is open, closed, opening, or closing.
|
||||||
@@ -72,6 +68,7 @@ public sealed class DoorComponent : Component
|
|||||||
/// Whether the door is currently partially closed or open. I.e., when the door is "closing" and is already opaque,
|
/// Whether the door is currently partially closed or open. I.e., when the door is "closing" and is already opaque,
|
||||||
/// but not yet actually closed.
|
/// but not yet actually closed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[DataField("partial")]
|
||||||
public bool Partial;
|
public bool Partial;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -142,9 +139,38 @@ public sealed class DoorComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of EntityUids of entities we're currently crushing. Cleared in OnPartialOpen().
|
/// List of EntityUids of entities we're currently crushing. Cleared in OnPartialOpen().
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[DataField("currentlyCrushing")]
|
||||||
public List<EntityUid> CurrentlyCrushing = new();
|
public List<EntityUid> CurrentlyCrushing = new();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Serialization
|
||||||
|
/// <summary>
|
||||||
|
/// Time until next state change. Because apparently <see cref="IGameTiming.CurTime"/> might not get saved/restored.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("SecondsUntilStateChange")]
|
||||||
|
private float? _secondsUntilStateChange;
|
||||||
|
|
||||||
|
void ISerializationHooks.BeforeSerialization()
|
||||||
|
{
|
||||||
|
if (NextStateChange == null)
|
||||||
|
{
|
||||||
|
_secondsUntilStateChange = null;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
var curTime = IoCManager.Resolve<IGameTiming>().CurTime;
|
||||||
|
_secondsUntilStateChange = (float) (NextStateChange.Value - curTime).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISerializationHooks.AfterDeserialization()
|
||||||
|
{
|
||||||
|
if (_secondsUntilStateChange == null || _secondsUntilStateChange.Value > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NextStateChange = IoCManager.Resolve<IGameTiming>().CurTime + TimeSpan.FromSeconds(_secondsUntilStateChange.Value);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
[DataField("board", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
[DataField("board", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
public string? BoardPrototype;
|
public string? BoardPrototype;
|
||||||
|
|
||||||
|
|||||||
@@ -6,16 +6,10 @@ using Content.Shared.Hands.Components;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Stunnable;
|
using Content.Shared.Stunnable;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Physics.Dynamics;
|
using Robust.Shared.Physics.Dynamics;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Shared.Doors.Systems;
|
namespace Content.Shared.Doors.Systems;
|
||||||
@@ -59,18 +53,33 @@ public abstract class SharedDoorSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<DoorComponent, PreventCollideEvent>(PreventCollision);
|
SubscribeLocalEvent<DoorComponent, PreventCollideEvent>(PreventCollision);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnInit(EntityUid uid, DoorComponent door, ComponentInit args)
|
private void OnInit(EntityUid uid, DoorComponent door, ComponentInit args)
|
||||||
{
|
{
|
||||||
// if the door state is not standard (i.e., door starts open), make sure collision & occlusion are properly set.
|
if (door.NextStateChange != null)
|
||||||
if (door.State == DoorState.Open)
|
_activeDoors.Add(door);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (TryComp(uid, out PhysicsComponent? physics))
|
// Make sure doors are not perpetually stuck opening or closing.
|
||||||
physics.CanCollide = false;
|
if (door.State == DoorState.Opening)
|
||||||
|
{
|
||||||
if (door.Occludes && TryComp(uid, out OccluderComponent? occluder))
|
// force to open.
|
||||||
occluder.Enabled = false;
|
door.State = DoorState.Open;
|
||||||
|
door.Partial = false;
|
||||||
|
}
|
||||||
|
if (door.State == DoorState.Closing)
|
||||||
|
{
|
||||||
|
// force to closed.
|
||||||
|
door.State = DoorState.Closed;
|
||||||
|
door.Partial = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should this door have collision and the like enabled?
|
||||||
|
var collidable = door.State == DoorState.Closed
|
||||||
|
|| door.State == DoorState.Closing && door.Partial
|
||||||
|
|| door.State == DoorState.Opening && !door.Partial;
|
||||||
|
|
||||||
|
SetCollidable(uid, collidable, door);
|
||||||
UpdateAppearance(uid, door);
|
UpdateAppearance(uid, door);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,21 +277,17 @@ public abstract class SharedDoorSystem : EntitySystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the door is partially opened. The door becomes transparent and stops colliding with entities.
|
/// Called when the door is partially opened. The door becomes transparent and stops colliding with entities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void OnPartialOpen(EntityUid uid, DoorComponent? door = null, PhysicsComponent? physics = null)
|
public void OnPartialOpen(EntityUid uid, DoorComponent? door = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref door, ref physics))
|
if (!Resolve(uid, ref door))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// we can't be crushing anyone anymore, since we're opening
|
SetCollidable(uid, false, door);
|
||||||
door.CurrentlyCrushing.Clear();
|
|
||||||
physics.CanCollide = false;
|
|
||||||
door.Partial = true;
|
door.Partial = true;
|
||||||
door.NextStateChange = GameTiming.CurTime + door.CloseTimeTwo;
|
door.NextStateChange = GameTiming.CurTime + door.CloseTimeTwo;
|
||||||
_activeDoors.Add(door);
|
_activeDoors.Add(door);
|
||||||
door.Dirty();
|
door.Dirty();
|
||||||
|
|
||||||
if (door.Occludes && TryComp(uid, out OccluderComponent? occluder))
|
|
||||||
occluder.Enabled = false;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -327,11 +332,12 @@ public abstract class SharedDoorSystem : EntitySystem
|
|||||||
/// Called when the door is partially closed. This is when the door becomes "solid". If this process fails (e.g., a
|
/// Called when the door is partially closed. This is when the door becomes "solid". If this process fails (e.g., a
|
||||||
/// mob entered the door as it was closing), then this returns false. Otherwise, returns true;
|
/// mob entered the door as it was closing), then this returns false. Otherwise, returns true;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool OnPartialClose(EntityUid uid, DoorComponent? door = null, PhysicsComponent? physics = null)
|
public bool OnPartialClose(EntityUid uid, DoorComponent? door = null, PhysicsComponent? physics = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref door, ref physics))
|
if (!Resolve(uid, ref door, ref physics))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
SetCollidable(uid, true, door, physics);
|
||||||
door.Partial = true;
|
door.Partial = true;
|
||||||
door.Dirty();
|
door.Dirty();
|
||||||
|
|
||||||
@@ -344,13 +350,9 @@ public abstract class SharedDoorSystem : EntitySystem
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
physics.CanCollide = true;
|
|
||||||
door.NextStateChange = GameTiming.CurTime + door.CloseTimeTwo;
|
door.NextStateChange = GameTiming.CurTime + door.CloseTimeTwo;
|
||||||
_activeDoors.Add(door);
|
_activeDoors.Add(door);
|
||||||
|
|
||||||
if (door.Occludes && TryComp(uid, out OccluderComponent? occluder))
|
|
||||||
occluder.Enabled = true;
|
|
||||||
|
|
||||||
// Crush any entities. Note that we don't check airlock safety here. This should have been checked before
|
// Crush any entities. Note that we don't check airlock safety here. This should have been checked before
|
||||||
// the door closed.
|
// the door closed.
|
||||||
Crush(uid, door, physics);
|
Crush(uid, door, physics);
|
||||||
@@ -359,6 +361,24 @@ public abstract class SharedDoorSystem : EntitySystem
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Collisions
|
#region Collisions
|
||||||
|
protected virtual void SetCollidable(EntityUid uid, bool collidable,
|
||||||
|
DoorComponent? door = null,
|
||||||
|
PhysicsComponent? physics = null,
|
||||||
|
OccluderComponent? occluder = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref door))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Resolve(uid, ref physics, false))
|
||||||
|
physics.CanCollide = collidable;
|
||||||
|
|
||||||
|
if (!collidable)
|
||||||
|
door.CurrentlyCrushing.Clear();
|
||||||
|
|
||||||
|
if (door.Occludes && Resolve(uid, ref occluder, false))
|
||||||
|
occluder.Enabled = collidable;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Crushes everyone colliding with us by more than <see cref="IntersectPercentage"/>%.
|
/// Crushes everyone colliding with us by more than <see cref="IntersectPercentage"/>%.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user