Files
RobustToolbox/Robust.Shared/GameObjects/Component.cs
slarticodefast 4747e5a05a Add and update a lot of documentation (#6337)
* Serialization docs

Co-authored-by: Moony <moonheart08@users.noreply.github.com>

* ECS docs

Co-authored-by: Moony <moonheart08@users.noreply.github.com>

* scattered docs

Co-authored-by: Moony <moonheart08@users.noreply.github.com>

* Fixes

---------

Co-authored-by: Moony <moonheart08@users.noreply.github.com>
Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
2025-12-15 20:26:17 +01:00

235 lines
7.0 KiB
C#

using System;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
namespace Robust.Shared.GameObjects
{
/// <summary>
/// The base class for all ECS components. A component is a piece of data, ideally without methods, that is
/// attached to or will be attached to some <see cref="EntityUid"/>. Entities do not have any data without
/// components to specify it.
/// </summary>
/// <remarks>
/// <para>
/// Components must be registered, usually with <see cref="RegisterComponentAttribute"/>, for the ECS to
/// recognize them.
/// </para>
/// <para>
/// Components implicitly have <see cref="DataDefinitionAttribute"/>, and are always valid for YAML ser/de.
/// </para>
/// </remarks>
/// <seealso cref="NetworkedComponentAttribute"/>
/// <seealso cref="DataFieldAttribute"/>
/// <seealso cref="ComponentState"/>
/// <seealso cref="UnsavedComponentAttribute"/>
[Reflect(false)]
[ImplicitDataDefinitionForInheritors]
public abstract partial class Component : IComponent
{
[DataField("netsync")]
[ViewVariables(VVAccess.ReadWrite)]
private bool _netSync { get; set; } = true;
internal bool Networked { get; set; } = true;
bool IComponent.Networked
{
get => Networked;
set => Networked = value;
}
/// <inheritdoc />
public bool NetSyncEnabled
{
get => Networked && _netSync;
set => _netSync = value;
}
/// <inheritdoc />
[ViewVariables]
[Obsolete("Update your API to allow accessing Owner through other means")]
public EntityUid Owner { get; set; } = EntityUid.Invalid;
[ViewVariables]
public ComponentLifeStage LifeStage { get; internal set; } = ComponentLifeStage.PreAdd;
ComponentLifeStage IComponent.LifeStage
{
get => LifeStage;
set => LifeStage = value;
}
public virtual bool SendOnlyToOwner => false;
public virtual bool SessionSpecific => false;
/// <inheritdoc />
[ViewVariables]
public bool Initialized => LifeStage >= ComponentLifeStage.Initializing;
/// <inheritdoc />
[ViewVariables]
public bool Running => ComponentLifeStage.Starting <= LifeStage && LifeStage <= ComponentLifeStage.Stopping;
/// <inheritdoc />
[ViewVariables]
public bool Deleted => LifeStage >= ComponentLifeStage.Removing;
/// <summary>
/// This is the tick the component was created.
/// </summary>
[ViewVariables]
public GameTick CreationTick { get; internal set; }
GameTick IComponent.CreationTick
{
get => CreationTick;
set => CreationTick = value;
}
/// <summary>
/// Marks the component as dirty so that the network will re-sync it with clients.
/// </summary>
[ViewVariables]
public GameTick LastModifiedTick { get; internal set; }
GameTick IComponent.LastModifiedTick
{
get => LastModifiedTick;
set => LastModifiedTick = value;
}
/// <inheritdoc />
[Obsolete]
public void Dirty(IEntityManager? entManager = null)
{
IoCManager.Resolve(ref entManager);
entManager.Dirty(Owner, this);
}
// these two methods clear the LastModifiedTick/CreationTick to mark it as "not different from prototype load".
// This is used as optimization in the game state system to avoid sending redundant component data.
void IComponent.ClearTicks()
{
ClearTicks();
}
private protected virtual void ClearTicks()
{
LastModifiedTick = GameTick.Zero;
ClearCreationTick();
}
void IComponent.ClearCreationTick()
{
ClearCreationTick();
}
private protected void ClearCreationTick()
{
CreationTick = GameTick.Zero;
}
}
/// <summary>
/// The life stages of an ECS component.
/// </summary>
public enum ComponentLifeStage : byte
{
/// <summary>
/// The component has just been allocated.
/// </summary>
PreAdd = 0,
/// <summary>
/// Currently being added to an entity.
/// </summary>
Adding,
/// <summary>
/// Has been added to an entity.
/// </summary>
Added,
/// <summary>
/// Currently being initialized.
/// </summary>
Initializing,
/// <summary>
/// Has been initialized.
/// </summary>
Initialized,
/// <summary>
/// Currently being started up.
/// </summary>
Starting,
/// <summary>
/// Has started up.
/// </summary>
Running,
/// <summary>
/// Currently shutting down.
/// </summary>
Stopping,
/// <summary>
/// Has been shut down.
/// </summary>
Stopped,
/// <summary>
/// Currently being removed from its entity.
/// </summary>
Removing,
/// <summary>
/// Removed from its entity, and is deleted.
/// </summary>
Deleted,
}
/// <summary>
/// WARNING: Do not subscribe to this unless you know what you are doing!
/// The component has been added to the entity. This is the first function
/// to be called after the component has been allocated and (optionally) deserialized.
/// </summary>
[ComponentEvent]
public readonly record struct ComponentAdd;
/// <summary>
/// Raised when all of the entity's other components have been added and are available,
/// But are not necessarily initialized yet. DO NOT depend on the values of other components to be correct.
/// </summary>
[ComponentEvent]
public sealed class ComponentInit : EntityEventArgs { }
/// <summary>
/// Starts up a component. This is called automatically after all components are Initialized and the entity is Initialized.
/// This can be called multiple times during the component's life, and at any time.
/// </summary>
[ComponentEvent]
public sealed class ComponentStartup : EntityEventArgs { }
/// <summary>
/// Shuts down the component. The is called Automatically by OnRemove. This can be called multiple times during
/// the component's life, and at any time.
/// </summary>
[ComponentEvent]
public sealed class ComponentShutdown : EntityEventArgs { }
/// <summary>
/// The component has been removed from the entity. This is the last function
/// that is called before the component is freed.
/// </summary>
[ComponentEvent]
public sealed class ComponentRemove : EntityEventArgs { }
}