Modernize GhostComponent & Ghost API (#36858)
* Move CanReturnToBody to system * Move CanGhostInteract to system * Cleanup redundant datafields and viewvariables * Document datafields * Document component * Add SetTimeOfDeath Entity<T> overload, obsolete old version * Document public methods * Cleanup obsoleted method calls
This commit is contained in:
@@ -117,6 +117,6 @@ public sealed class AGhostCommand : LocalizedCommands
|
|||||||
}
|
}
|
||||||
|
|
||||||
var comp = _entities.GetComponent<GhostComponent>(ghost);
|
var comp = _entities.GetComponent<GhostComponent>(ghost);
|
||||||
ghostSystem.SetCanReturnToBody(comp, canReturn);
|
ghostSystem.SetCanReturnToBody((ghost, comp), canReturn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -489,10 +489,10 @@ namespace Content.Server.Ghost
|
|||||||
|
|
||||||
if (mind.Comp.TimeOfDeath.HasValue)
|
if (mind.Comp.TimeOfDeath.HasValue)
|
||||||
{
|
{
|
||||||
SetTimeOfDeath(ghost, mind.Comp.TimeOfDeath!.Value, ghostComponent);
|
SetTimeOfDeath((ghost, ghostComponent), mind.Comp.TimeOfDeath!.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCanReturnToBody(ghostComponent, canReturn);
|
SetCanReturnToBody((ghost, ghostComponent), canReturn);
|
||||||
|
|
||||||
if (canReturn)
|
if (canReturn)
|
||||||
_minds.Visit(mind.Owner, ghost, mind.Comp);
|
_minds.Visit(mind.Owner, ghost, mind.Comp);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public sealed class MindSystem : SharedMindSystem
|
|||||||
{
|
{
|
||||||
TransferTo(mindId, visiting, mind: mind);
|
TransferTo(mindId, visiting, mind: mind);
|
||||||
if (TryComp(visiting, out GhostComponent? ghostComp))
|
if (TryComp(visiting, out GhostComponent? ghostComp))
|
||||||
_ghosts.SetCanReturnToBody(ghostComp, false);
|
_ghosts.SetCanReturnToBody((visiting, ghostComp), false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ public sealed class MindSystem : SharedMindSystem
|
|||||||
entity = Spawn(GameTicker.ObserverPrototypeName, position);
|
entity = Spawn(GameTicker.ObserverPrototypeName, position);
|
||||||
component = EnsureComp<MindContainerComponent>(entity.Value);
|
component = EnsureComp<MindContainerComponent>(entity.Value);
|
||||||
var ghostComponent = Comp<GhostComponent>(entity.Value);
|
var ghostComponent = Comp<GhostComponent>(entity.Value);
|
||||||
_ghosts.SetCanReturnToBody(ghostComponent, false);
|
_ghosts.SetCanReturnToBody((entity.Value, ghostComponent), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldEntity = mind.OwnedEntity;
|
var oldEntity = mind.OwnedEntity;
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ using Robust.Shared.Prototypes;
|
|||||||
|
|
||||||
namespace Content.Shared.Ghost;
|
namespace Content.Shared.Ghost;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an observer ghost.
|
||||||
|
/// Handles limiting interactions, using ghost abilities, ghost visibility, and ghost warping.
|
||||||
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedGhostSystem))]
|
[RegisterComponent, NetworkedComponent, Access(typeof(SharedGhostSystem))]
|
||||||
[AutoGenerateComponentState(true), AutoGenerateComponentPause]
|
[AutoGenerateComponentState(true), AutoGenerateComponentPause]
|
||||||
public sealed partial class GhostComponent : Component
|
public sealed partial class GhostComponent : Component
|
||||||
@@ -41,46 +45,47 @@ public sealed partial class GhostComponent : Component
|
|||||||
|
|
||||||
// End actions
|
// End actions
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField, AutoPausedField]
|
/// <summary>
|
||||||
|
/// Time at which the player died and created this ghost.
|
||||||
|
/// Used to determine votekick eligibility.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// May not reflect actual time of death if this entity has been paused,
|
||||||
|
/// but will give an accurate length of time <i>since</i> death.
|
||||||
|
/// </remarks>
|
||||||
|
[DataField, AutoPausedField]
|
||||||
public TimeSpan TimeOfDeath = TimeSpan.Zero;
|
public TimeSpan TimeOfDeath = TimeSpan.Zero;
|
||||||
|
|
||||||
[DataField("booRadius"), ViewVariables(VVAccess.ReadWrite)]
|
/// <summary>
|
||||||
|
/// Range of the Boo action.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
public float BooRadius = 3;
|
public float BooRadius = 3;
|
||||||
|
|
||||||
[DataField("booMaxTargets"), ViewVariables(VVAccess.ReadWrite)]
|
/// <summary>
|
||||||
|
/// Maximum number of entities that can affected by the Boo action.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
public int BooMaxTargets = 3;
|
public int BooMaxTargets = 3;
|
||||||
|
|
||||||
// TODO: instead of this funny stuff just give it access and update in system dirtying when needed
|
/// <summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// Is this ghost allowed to interact with entities?
|
||||||
public bool CanGhostInteract
|
/// </summary>
|
||||||
{
|
/// <remarks>
|
||||||
get => _canGhostInteract;
|
/// Used to allow admins ghosts to interact with the world.
|
||||||
set
|
/// Changed by <see cref="SharedGhostSystem.SetCanGhostInteract"/>.
|
||||||
{
|
/// </remarks>
|
||||||
if (_canGhostInteract == value) return;
|
|
||||||
_canGhostInteract = value;
|
|
||||||
Dirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataField("canInteract"), AutoNetworkedField]
|
[DataField("canInteract"), AutoNetworkedField]
|
||||||
private bool _canGhostInteract;
|
public bool CanGhostInteract;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changed by <see cref="SharedGhostSystem.SetCanReturnToBody"/>
|
/// Is this ghost player allowed to return to their original body?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// TODO MIRROR change this to use friend classes when thats merged
|
/// <remarks>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// Changed by <see cref="SharedGhostSystem.SetCanReturnToBody"/>.
|
||||||
public bool CanReturnToBody
|
/// </remarks>
|
||||||
{
|
[DataField, AutoNetworkedField]
|
||||||
get => _canReturnToBody;
|
public bool CanReturnToBody;
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_canReturnToBody == value) return;
|
|
||||||
_canReturnToBody = value;
|
|
||||||
Dirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ghost color
|
/// Ghost color
|
||||||
@@ -88,9 +93,6 @@ public sealed partial class GhostComponent : Component
|
|||||||
/// <remarks>Used to allow admins to change ghost colors. Should be removed if the capability to edit existing sprite colors is ever added back.</remarks>
|
/// <remarks>Used to allow admins to change ghost colors. Should be removed if the capability to edit existing sprite colors is ever added back.</remarks>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public Color Color = Color.White;
|
public Color Color = Color.White;
|
||||||
|
|
||||||
[DataField("canReturnToBody"), AutoNetworkedField]
|
|
||||||
private bool _canReturnToBody;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed partial class ToggleFoVActionEvent : InstantActionEvent { }
|
public sealed partial class ToggleFoVActionEvent : InstantActionEvent { }
|
||||||
|
|||||||
@@ -37,25 +37,68 @@ namespace Content.Shared.Ghost
|
|||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the ghost's time of death.
|
||||||
|
/// </summary>
|
||||||
|
public void SetTimeOfDeath(Entity<GhostComponent?> entity, TimeSpan value)
|
||||||
|
{
|
||||||
|
if (!Resolve(entity, ref entity.Comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (entity.Comp.TimeOfDeath == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entity.Comp.TimeOfDeath = value;
|
||||||
|
Dirty(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use the Entity<GhostComponent?> overload")]
|
||||||
public void SetTimeOfDeath(EntityUid uid, TimeSpan value, GhostComponent? component)
|
public void SetTimeOfDeath(EntityUid uid, TimeSpan value, GhostComponent? component)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component))
|
SetTimeOfDeath((uid, component), value);
|
||||||
return;
|
|
||||||
|
|
||||||
component.TimeOfDeath = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not the ghost player is allowed to return to their original body.
|
||||||
|
/// </summary>
|
||||||
|
public void SetCanReturnToBody(Entity<GhostComponent?> entity, bool value)
|
||||||
|
{
|
||||||
|
if (!Resolve(entity, ref entity.Comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (entity.Comp.CanReturnToBody == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entity.Comp.CanReturnToBody = value;
|
||||||
|
Dirty(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use the Entity<GhostComponent?> overload")]
|
||||||
public void SetCanReturnToBody(EntityUid uid, bool value, GhostComponent? component = null)
|
public void SetCanReturnToBody(EntityUid uid, bool value, GhostComponent? component = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component))
|
SetCanReturnToBody((uid, component), value);
|
||||||
return;
|
|
||||||
|
|
||||||
component.CanReturnToBody = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use the Entity<GhostComponent?> overload")]
|
||||||
public void SetCanReturnToBody(GhostComponent component, bool value)
|
public void SetCanReturnToBody(GhostComponent component, bool value)
|
||||||
{
|
{
|
||||||
component.CanReturnToBody = value;
|
SetCanReturnToBody((component.Owner, component), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether the ghost is allowed to interact with other entities.
|
||||||
|
/// </summary>
|
||||||
|
public void SetCanGhostInteract(Entity<GhostComponent?> entity, bool value)
|
||||||
|
{
|
||||||
|
if (!Resolve(entity, ref entity.Comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (entity.Comp.CanGhostInteract == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entity.Comp.CanGhostInteract = value;
|
||||||
|
Dirty(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user