using System; using Robust.Client.GameObjects; using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Network; using Robust.Shared.Players; using Robust.Shared.ViewVariables; namespace Robust.Client.Player { /// /// Variables and functions that deal with the local client's session. /// public sealed class LocalPlayer { /// /// An entity has been attached to the local player. /// public event Action? EntityAttached; /// /// An entity has been detached from the local player. /// public event Action? EntityDetached; /// /// 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 NetUserId UserId { get; set; } /// /// Session of the local client. /// [ViewVariables] public ICommonSession Session => InternalSession; internal PlayerSession InternalSession { get; set; } = default!; /// /// OOC name of the local player. /// [ViewVariables] public string Name { get; set; } = default!; /// /// The status of the client's session has changed. /// public event EventHandler? StatusChanged; /// /// Attaches a client to an entity. /// /// Entity to attach the client to. public void AttachEntity(EntityUid entity) { // Detach and cleanup first DetachEntity(); ControlledEntity = entity; InternalSession.AttachedEntity = entity; var entMan = IoCManager.Resolve(); if (!entMan.TryGetComponent(entity, out var eye)) { eye = entMan.AddComponent(entity); } eye.Current = true; EntityAttached?.Invoke(new EntityAttachedEventArgs(entity)); // notify ECS Systems var eventBus = entMan.EventBus; eventBus.RaiseEvent(EventSource.Local, new PlayerAttachSysMessage(entity)); eventBus.RaiseLocalEvent(entity, new PlayerAttachedEvent(entity)); } /// /// Detaches the client from an entity. /// public void DetachEntity() { var entMan = IoCManager.Resolve(); var previous = ControlledEntity; if (entMan.TryGetComponent(previous, out MetaDataComponent? metaData) && metaData.EntityInitialized && !metaData.EntityDeleted) { entMan.GetComponent(previous.Value).Current = false; // notify ECS Systems entMan.EventBus.RaiseEvent(EventSource.Local, new PlayerAttachSysMessage(default)); entMan.EventBus.RaiseLocalEvent(previous.Value, new PlayerDetachedEvent(previous.Value)); } ControlledEntity = default; if (previous != null) { EntityDetached?.Invoke(new EntityDetachedEventArgs(previous.Value)); } } /// /// Changes the state of the session. /// public void SwitchState(SessionStatus newStatus) { SwitchState(Session.Status, newStatus); } /// /// Changes the state of the session. This overload allows you to spoof the oldStatus, use with caution. /// public void SwitchState(SessionStatus oldStatus, SessionStatus newStatus) { var args = new StatusEventArgs(oldStatus, newStatus); Session.Status = newStatus; StatusChanged?.Invoke(this, args); } } /// /// Event arguments for when the status of a session changes. /// public sealed class StatusEventArgs : EventArgs { /// /// Status that the session switched from. /// public SessionStatus OldStatus { get; } /// /// Status that the session switched to. /// public SessionStatus NewStatus { get; } /// /// Constructs a new instance of the class. /// public StatusEventArgs(SessionStatus oldStatus, SessionStatus newStatus) { OldStatus = oldStatus; NewStatus = newStatus; } } public sealed class EntityDetachedEventArgs : EventArgs { public EntityDetachedEventArgs(EntityUid oldEntity) { OldEntity = oldEntity; } public EntityUid OldEntity { get; } } public sealed class EntityAttachedEventArgs : EventArgs { public EntityAttachedEventArgs(EntityUid newEntity) { NewEntity = newEntity; } public EntityUid NewEntity { get; } } }