using System; using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; using SS14.Server.Interfaces.Player; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.IoC; using SS14.Shared.Network; using SS14.Shared.ViewVariables; namespace Content.Server.Mobs { /// /// A mind represents the IC "mind" of a player. Stores roles currently. /// /// /// Think of it like this: if a player is supposed to have their memories, /// their mind follows along. /// /// Things such as respawning do not follow, because you're a new character. /// Getting borged, cloned, turned into a catbeast, etc... will keep it following you. /// public sealed class Mind { private readonly Dictionary _roles = new Dictionary(); /// /// Creates the new mind attached to a specific player session. /// /// The session ID of the owning player. public Mind(NetSessionId sessionId) { SessionId = sessionId; } // TODO: This session should be able to be changed, probably. /// /// The session ID of the player owning this mind. /// [ViewVariables] public NetSessionId SessionId { get; } [ViewVariables] public bool IsVisitingEntity => VisitingEntity != null; [ViewVariables] public IEntity VisitingEntity { get; private set; } [ViewVariables] public IEntity CurrentEntity => VisitingEntity ?? OwnedEntity; /// /// The component currently owned by this mind. /// Can be null. /// [ViewVariables] public MindComponent OwnedMob { get; private set; } /// /// The entity currently owned by this mind. /// Can be null. /// [ViewVariables] public IEntity OwnedEntity => OwnedMob?.Owner; /// /// An enumerable over all the roles this mind has. /// [ViewVariables] public IEnumerable AllRoles => _roles.Values; /// /// The session of the player owning this mind. /// Can be null, in which case the player is currently not logged in. /// [ViewVariables] public IPlayerSession Session { get { var playerMgr = IoCManager.Resolve(); playerMgr.TryGetSessionById(SessionId, out var ret); return ret; } } /// /// Gives this mind a new role. /// /// The type of the role to give. /// The instance of the role. /// /// Thrown if we already have a role with this type. /// public T AddRole() where T : Role { return (T)AddRole(typeof(T)); } /// /// Gives this mind a new role. /// /// The type of the role to give. /// The instance of the role. /// /// Thrown if we already have a role with this type. /// public Role AddRole(Type t) { if (_roles.ContainsKey(t)) { throw new ArgumentException($"We already have this role: {t}"); } var role = (Role)Activator.CreateInstance(t, this); _roles[t] = role; role.Greet(); return role; } /// /// Removes a role from this mind. /// /// The type of the role to remove. /// /// Thrown if we do not have this role. /// public void RemoveRole() where T : Role { RemoveRole(typeof(T)); } /// /// Removes a role from this mind. /// /// The type of the role to remove. /// /// Thrown if we do not have this role. /// public void RemoveRole(Type t) { if (!_roles.ContainsKey(t)) { throw new ArgumentException($"We do not have this role: {t}"); } // This can definitely get more complex removal hooks later, // when we need it. _roles.Remove(t); } /// /// Gets a role of a certain type. /// /// The type of the role to get. /// The role's instance. /// /// Thrown if we do not have a role of this type. /// public T GetRole() where T : Role { return (T)_roles[typeof(T)]; } /// /// Gets a role of a certain type. /// /// The type of the role to get. /// The role's instance. /// /// Thrown if we do not have a role of this type. /// public Role GetRole(Type t) { return _roles[t]; } /// /// Transfer this mind's control over to a new entity. /// /// /// The entity to control. /// Can be null, in which case it will simply detach the mind from any entity. /// /// /// Thrown if is already owned by another mind. /// public void TransferTo(IEntity entity) { MindComponent component = null; if (entity != null) { if (!entity.TryGetComponent(out component)) { component = entity.AddComponent(); } else if (component.HasMind) { // TODO: Kick them out, maybe? throw new ArgumentException("That entity already has a mind.", nameof(entity)); } } OwnedMob?.InternalEjectMind(); OwnedMob = component; OwnedMob?.InternalAssignMind(this); // Player is CURRENTLY connected. if (Session != null && OwnedMob != null) { Session.AttachToEntity(entity); } VisitingEntity = null; } public void Visit(IEntity entity) { Session?.AttachToEntity(entity); VisitingEntity = entity; } public void UnVisit() { if (!IsVisitingEntity) { return; } Session?.AttachToEntity(OwnedEntity); VisitingEntity = null; } } }