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;
}
}
}