using JetBrains.Annotations; using Robust.Shared.GameStates; using Robust.Shared.IoC; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Timing; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; using System; namespace Robust.Shared.GameObjects { /// /// Serialized state of a . /// [Serializable, NetSerializable] public sealed class MetaDataComponentState : ComponentState { /// /// The in-game name of this entity. /// public string? Name { get; } /// /// The in-game description of this entity. /// public string? Description { get; } /// /// The prototype this entity was created from, if any. /// public string? PrototypeId { get; } /// /// When this entity was paused. /// public TimeSpan? PauseTime; /// /// Constructs a new instance of . /// /// The in-game name of this entity. /// The in-game description of this entity. /// The prototype this entity was created from, if any. /// When this entity was paused. public MetaDataComponentState(string? name, string? description, string? prototypeId, TimeSpan? pauseTime) { Name = name; Description = description; PrototypeId = prototypeId; PauseTime = pauseTime; } } /// /// Contains meta data about this entity that isn't component specific. /// [RegisterComponent, NetworkedComponent] public sealed class MetaDataComponent : Component { [DataField("name")] internal string? _entityName; [DataField("desc")] internal string? _entityDescription; internal EntityPrototype? _entityPrototype; /// /// When this entity was paused, if applicable /// internal TimeSpan? PauseTime; // Every entity starts at tick 1, because they are conceptually created in the time between 0->1 [ViewVariables] public GameTick EntityLastModifiedTick { get; internal set; } = new(1); /// /// This is the tick at which the client last applied state data received from the server. /// [ViewVariables] public GameTick LastStateApplied { get; internal set; } = GameTick.Zero; /// /// This is the most recent tick at which some component was removed from this entity. /// [ViewVariables] public GameTick LastComponentRemoved { get; internal set; } = GameTick.Zero; /// /// The in-game name of this entity. /// [ViewVariables(VVAccess.ReadWrite)] public string EntityName { get { if (_entityName == null) return _entityPrototype != null ? _entityPrototype.Name : string.Empty; return _entityName; } [Obsolete("Use MetaDataSystem.SetEntityName")] set { if (value == EntityName) return; IoCManager.Resolve().GetEntitySystem().SetEntityName(Owner, value, this); } } /// /// The in-game description of this entity. /// [ViewVariables(VVAccess.ReadWrite)] public string EntityDescription { get { if (_entityDescription == null) return _entityPrototype != null ? _entityPrototype.Description : string.Empty; return _entityDescription; } [Obsolete("Use MetaDataSystem.SetEntityDescription")] set { if (value == EntityDescription) return; IoCManager.Resolve().GetEntitySystem().SetEntityDescription(Owner, value, this); } } /// /// The prototype this entity was created from, if any. /// [ViewVariables] public EntityPrototype? EntityPrototype { get => _entityPrototype; [Obsolete("Use MetaDataSystem.SetEntityPrototype")] set { _entityPrototype = value; Dirty(); } } /// /// The current lifetime stage of this entity. You can use this to check /// if the entity is initialized or being deleted. /// [ViewVariables] public EntityLifeStage EntityLifeStage { get; internal set; } [DataField("flags")] public MetaDataFlags Flags { get => _flags; internal set { if (_flags == value) return; // In container and detached to null are mutually exclusive flags. DebugTools.Assert((value & (MetaDataFlags.InContainer | MetaDataFlags.Detached)) != (MetaDataFlags.InContainer | MetaDataFlags.Detached)); _flags = value; } } internal MetaDataFlags _flags; /// /// The sum of our visibility layer and our parent's visibility layers. /// /// /// Every entity will always have the first bit set to true. /// [Access(typeof(MetaDataSystem))] public int VisibilityMask = 1; [UsedImplicitly, ViewVariables(VVAccess.ReadWrite)] private int VVVisibilityMask { get => VisibilityMask; set => IoCManager.Resolve().GetEntitySystem().SetVisibilityMask(Owner, value, this); } [ViewVariables] public bool EntityPaused => PauseTime != null; public bool EntityInitialized => EntityLifeStage >= EntityLifeStage.Initialized; public bool EntityInitializing => EntityLifeStage == EntityLifeStage.Initializing; public bool EntityDeleted => EntityLifeStage >= EntityLifeStage.Deleted; internal override void ClearTicks() { // Do not clear modified ticks. // MetaDataComponent is used in the game state system to carry initial data like prototype ID. // So it ALWAYS has to be sent. // (Creation can still be cleared though) ClearCreationTick(); } } [Flags] public enum MetaDataFlags : byte { None = 0, /// /// Whether the entity has any component that has state information specific to particular players. /// SessionSpecific = 1 << 0, /// /// Whether the entity is currently inside of a container. /// InContainer = 1 << 1, /// /// Used by clients to indicate that an entity has left their visible set. /// Detached = 1 << 2, } }