diff --git a/Robust.Client/Placement/PlacementManager.cs b/Robust.Client/Placement/PlacementManager.cs index e328ca101b..452b144e89 100644 --- a/Robust.Client/Placement/PlacementManager.cs +++ b/Robust.Client/Placement/PlacementManager.cs @@ -492,8 +492,7 @@ namespace Robust.Client.Placement { // Try to get current map. var map = MapId.Nullspace; - var ent = PlayerManager.LocalPlayer!.ControlledEntity; - if (ent != default) + if (PlayerManager.LocalPlayer!.ControlledEntity is {Valid: true} ent) { map = EntityManager.GetComponent(ent).MapID; } @@ -633,11 +632,12 @@ namespace Robust.Client.Placement CurrentMode.Render(handle); - if (CurrentPermission == null || CurrentPermission.Range <= 0 || !CurrentMode.RangeRequired - || PlayerManager.LocalPlayer?.ControlledEntity == null) + if (CurrentPermission is not {Range: > 0} || + !CurrentMode.RangeRequired || + PlayerManager.LocalPlayer?.ControlledEntity is not {Valid: true} controlled) return; - var worldPos = EntityManager.GetComponent(PlayerManager.LocalPlayer.ControlledEntity).WorldPosition; + var worldPos = EntityManager.GetComponent(controlled).WorldPosition; handle.DrawCircle(worldPos, CurrentPermission.Range, new Color(1, 1, 1, 0.25f)); } diff --git a/Robust.Client/Player/LocalPlayer.cs b/Robust.Client/Player/LocalPlayer.cs index 42e50e8d2f..8eaa11f2da 100644 --- a/Robust.Client/Player/LocalPlayer.cs +++ b/Robust.Client/Player/LocalPlayer.cs @@ -28,7 +28,7 @@ namespace Robust.Client.Player /// Game entity that the local player is controlling. If this is default, the player is not attached to any /// entity at all. /// - [ViewVariables] public EntityUid ControlledEntity { get; private set; } + [ViewVariables] public EntityUid? ControlledEntity { get; private set; } [ViewVariables] public NetUserId UserId { get; set; } @@ -86,20 +86,22 @@ namespace Robust.Client.Player { var entMan = IoCManager.Resolve(); var previous = ControlledEntity; - if (previous != default && entMan.EntityExists(previous)) + if (entMan.TryGetComponent(previous, out MetaDataComponent? metaData) && + metaData.EntityInitialized && + !metaData.EntityDeleted) { - entMan.GetComponent(previous).Current = false; + entMan.GetComponent(previous.Value).Current = false; // notify ECS Systems entMan.EventBus.RaiseEvent(EventSource.Local, new PlayerAttachSysMessage(default)); - entMan.EventBus.RaiseLocalEvent(previous, new PlayerDetachedEvent(previous)); + entMan.EventBus.RaiseLocalEvent(previous.Value, new PlayerDetachedEvent(previous.Value)); } ControlledEntity = default; - if (previous != default) + if (previous != null) { - EntityDetached?.Invoke(new EntityDetachedEventArgs(previous)); + EntityDetached?.Invoke(new EntityDetachedEventArgs(previous.Value)); } } diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index 3a214c1a4b..aa037fdc63 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -427,6 +427,13 @@ namespace Robust.Shared.GameObjects return HasComponent(uid, typeof(T)); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasComponent(EntityUid? uid) + { + return uid.HasValue && HasComponent(uid.Value, typeof(T)); + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasComponent(EntityUid uid, Type type) @@ -435,6 +442,19 @@ namespace Robust.Shared.GameObjects return dict.TryGetValue(uid, out var comp) && !comp.Deleted; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasComponent(EntityUid? uid, Type type) + { + if (!uid.HasValue) + { + return false; + } + + var dict = _entTraitDict[type]; + return dict.TryGetValue(uid.Value, out var comp) && !comp.Deleted; + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasComponent(EntityUid uid, ushort netId) @@ -443,6 +463,19 @@ namespace Robust.Shared.GameObjects && netSet.ContainsKey(netId); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasComponent(EntityUid? uid, ushort netId) + { + if (!uid.HasValue) + { + return false; + } + + return _netComponents.TryGetValue(uid.Value, out var netSet) + && netSet.ContainsKey(netId); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public T EnsureComponent(EntityUid uid) where T : Component, new() { @@ -497,6 +530,28 @@ namespace Robust.Shared.GameObjects return false; } + /// + public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out T component) + { + if (!uid.HasValue) + { + component = default!; + return false; + } + + if (TryGetComponent(uid.Value, typeof(T), out var comp)) + { + if (!comp.Deleted) + { + component = (T)comp; + return true; + } + } + + component = default!; + return false; + } + /// public bool TryGetComponent(EntityUid uid, Type type, [NotNullWhen(true)] out IComponent? component) { @@ -514,6 +569,29 @@ namespace Robust.Shared.GameObjects return false; } + /// + public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, Type type, [NotNullWhen(true)] out IComponent? component) + { + if (!uid.HasValue) + { + component = null; + return false; + } + + var dict = _entTraitDict[type]; + if (dict.TryGetValue(uid.Value, out var comp)) + { + if (!comp.Deleted) + { + component = comp; + return true; + } + } + + component = null; + return false; + } + /// public bool TryGetComponent(EntityUid uid, ushort netId, [MaybeNullWhen(false)] out IComponent component) { @@ -528,6 +606,26 @@ namespace Robust.Shared.GameObjects return false; } + /// + public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, [MaybeNullWhen(false)] out IComponent component) + { + if (!uid.HasValue) + { + component = default; + return false; + } + + if (_netComponents.TryGetValue(uid.Value, out var netSet) + && netSet.TryGetValue(netId, out var comp)) + { + component = comp; + return true; + } + + component = default; + return false; + } + /// public IEnumerable GetComponents(EntityUid uid) { diff --git a/Robust.Shared/GameObjects/EntityManager.cs b/Robust.Shared/GameObjects/EntityManager.cs index 91360a6082..d94685571d 100644 --- a/Robust.Shared/GameObjects/EntityManager.cs +++ b/Robust.Shared/GameObjects/EntityManager.cs @@ -305,6 +305,11 @@ namespace Robust.Shared.GameObjects return _entTraitDict[typeof(MetaDataComponent)].ContainsKey(uid); } + public bool EntityExists(EntityUid? uid) + { + return uid.HasValue && EntityExists(uid.Value); + } + /// /// Disposes all entities and clears all lists. /// diff --git a/Robust.Shared/GameObjects/EntitySystem.Proxy.cs b/Robust.Shared/GameObjects/EntitySystem.Proxy.cs index 8981051e3b..0fb68aa024 100644 --- a/Robust.Shared/GameObjects/EntitySystem.Proxy.cs +++ b/Robust.Shared/GameObjects/EntitySystem.Proxy.cs @@ -521,14 +521,14 @@ public partial class EntitySystem [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public EntityUid Spawn(string? prototype, EntityCoordinates coordinates) { - return EntityManager.SpawnEntity(prototype, coordinates).Uid; + return EntityManager.SpawnEntity(prototype, coordinates); } /// [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public EntityUid Spawn(string? prototype, MapCoordinates coordinates) { - return EntityManager.SpawnEntity(prototype, coordinates).Uid; + return EntityManager.SpawnEntity(prototype, coordinates); } #endregion diff --git a/Robust.Shared/GameObjects/IEntityManager.Components.cs b/Robust.Shared/GameObjects/IEntityManager.Components.cs index 2a13e0178f..b549cebf3f 100644 --- a/Robust.Shared/GameObjects/IEntityManager.Components.cs +++ b/Robust.Shared/GameObjects/IEntityManager.Components.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using JetBrains.Annotations; using Robust.Shared.Players; namespace Robust.Shared.GameObjects @@ -102,6 +101,14 @@ namespace Robust.Shared.GameObjects /// True if the entity has the component type, otherwise false. bool HasComponent(EntityUid uid); + /// + /// Checks if the entity has a component type. + /// + /// Component reference type to check for. + /// Entity UID to check. + /// True if the entity has the component type, otherwise false. + bool HasComponent(EntityUid? uid); + /// /// Checks if the entity has a component type. /// @@ -110,6 +117,14 @@ namespace Robust.Shared.GameObjects /// True if the entity has the component type, otherwise false. bool HasComponent(EntityUid uid, Type type); + /// + /// Checks if the entity has a component type. + /// + /// Entity UID to check. + /// A trait or component type to check for. + /// True if the entity has the component type, otherwise false. + bool HasComponent(EntityUid ?uid, Type type); + /// /// Checks if the entity has a component with a given network ID. This does not check /// if the component is deleted. @@ -119,6 +134,15 @@ namespace Robust.Shared.GameObjects /// True if the entity has a component with the given network ID, otherwise false. bool HasComponent(EntityUid uid, ushort netId); + /// + /// Checks if the entity has a component with a given network ID. This does not check + /// if the component is deleted. + /// + /// Entity UID to check. + /// Network ID to check for. + /// True if the entity has a component with the given network ID, otherwise false. + bool HasComponent(EntityUid? uid, ushort netId); + /// /// This method will always return a component for a certain entity, adding it if it's not there already. /// @@ -161,6 +185,15 @@ namespace Robust.Shared.GameObjects /// If the component existed in the entity. bool TryGetComponent(EntityUid uid, [NotNullWhen(true)] out T component); + /// + /// Returns the component of a specific type. + /// + /// A trait or type of a component to retrieve. + /// Entity UID to check. + /// Component of the specified type (if exists). + /// If the component existed in the entity. + bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out T component); + /// /// Returns the component of a specific type. /// @@ -170,6 +203,15 @@ namespace Robust.Shared.GameObjects /// If the component existed in the entity. bool TryGetComponent(EntityUid uid, Type type, [NotNullWhen(true)] out IComponent? component); + /// + /// Returns the component of a specific type. + /// + /// Entity UID to check. + /// A trait or component type to check for. + /// Component of the specified type (if exists). + /// If the component existed in the entity. + bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, Type type, [NotNullWhen(true)] out IComponent? component); + /// /// Returns the component with a specified network ID. This does not check /// if the component is deleted. @@ -180,6 +222,16 @@ namespace Robust.Shared.GameObjects /// If the component existed in the entity. bool TryGetComponent(EntityUid uid, ushort netId, [NotNullWhen(true)] out IComponent? component); + /// + /// Returns the component with a specified network ID. This does not check + /// if the component is deleted. + /// + /// Entity UID to check. + /// Component Network ID to check for. + /// Component with the specified network id. + /// If the component existed in the entity. + bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, [NotNullWhen(true)] out IComponent? component); + /// /// Returns ALL component type instances on an entity. A single component instance /// can have multiple component types. diff --git a/Robust.Shared/GameObjects/IEntityManager.cs b/Robust.Shared/GameObjects/IEntityManager.cs index 0b25e04e18..f9f2601016 100644 --- a/Robust.Shared/GameObjects/IEntityManager.cs +++ b/Robust.Shared/GameObjects/IEntityManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; using Prometheus; using Robust.Shared.Map; @@ -95,6 +96,11 @@ namespace Robust.Shared.GameObjects /// bool EntityExists(EntityUid uid); + /// + /// Checks whether an entity with the specified ID exists. + /// + bool EntityExists([NotNullWhen(true)] EntityUid? uid); + /// /// Returns a string representation of an entity with various information regarding it. ///