Cloning rework (#3808)
* Fix cloning * Fix cloning after clone dies and remove unneeded code * Fix ignored Co-authored-by: Silver <silvertorch5@gmail.com>
This commit is contained in:
@@ -253,6 +253,7 @@ namespace Content.Client
|
|||||||
"SpawnAfterInteract",
|
"SpawnAfterInteract",
|
||||||
"DisassembleOnActivate",
|
"DisassembleOnActivate",
|
||||||
"ExplosionLaunched",
|
"ExplosionLaunched",
|
||||||
|
"BeingCloned",
|
||||||
"Advertise",
|
"Advertise",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using Content.Server.Mobs;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Medical
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class BeingClonedComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "BeingCloned";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public Mind? Mind = default;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public EntityUid Parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
#nullable enable
|
|
||||||
using System;
|
using System;
|
||||||
using Content.Server.Eui;
|
using Content.Server.Eui;
|
||||||
using Content.Server.GameObjects.Components.Mobs;
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
@@ -10,14 +9,12 @@ using Content.Server.Mobs;
|
|||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
using Content.Shared.GameObjects.Components.Medical;
|
using Content.Shared.GameObjects.Components.Medical;
|
||||||
using Content.Shared.GameObjects.Components.Mobs.State;
|
using Content.Shared.GameObjects.Components.Mobs.State;
|
||||||
using Content.Shared.Interfaces.GameObjects.Components;
|
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -25,70 +22,42 @@ using Robust.Shared.ViewVariables;
|
|||||||
namespace Content.Server.GameObjects.Components.Medical
|
namespace Content.Server.GameObjects.Components.Medical
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(IActivate))]
|
public class CloningPodComponent : SharedCloningPodComponent
|
||||||
public class CloningPodComponent : SharedCloningPodComponent, IActivate
|
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IServerPreferencesManager _prefsManager = null!;
|
[Dependency] private readonly IServerPreferencesManager _prefsManager = null!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = null!;
|
[Dependency] private readonly IPlayerManager _playerManager = null!;
|
||||||
[Dependency] private readonly EuiManager _euiManager = null!;
|
[Dependency] private readonly EuiManager _euiManager = null!;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
public bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private BoundUserInterface? UserInterface =>
|
public BoundUserInterface? UserInterface =>
|
||||||
Owner.GetUIOrNull(CloningPodUIKey.Key);
|
Owner.GetUIOrNull(CloningPodUIKey.Key);
|
||||||
|
|
||||||
private ContainerSlot _bodyContainer = default!;
|
[ViewVariables] public ContainerSlot BodyContainer = default!;
|
||||||
private Mind? _capturedMind;
|
[ViewVariables] public Mind? CapturedMind;
|
||||||
private CloningPodStatus _status;
|
[ViewVariables] public float CloningProgress = 0;
|
||||||
private float _cloningProgress = 0;
|
|
||||||
[DataField("cloningTime")]
|
[DataField("cloningTime")]
|
||||||
private float _cloningTime = 120f;
|
[ViewVariables] public float CloningTime = 30f;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public CloningPodStatus Status;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
if (UserInterface != null)
|
if (UserInterface != null)
|
||||||
{
|
{
|
||||||
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
|
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
_bodyContainer = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, $"{Name}-bodyContainer");
|
BodyContainer = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, $"{Name}-bodyContainer");
|
||||||
|
|
||||||
//TODO: write this so that it checks for a change in power events for GORE POD cases
|
//TODO: write this so that it checks for a change in power events for GORE POD cases
|
||||||
var newState = GetUserInterfaceState();
|
if (UserInterface != null)
|
||||||
UserInterface?.SetState(newState);
|
EntitySystem.Get<CloningSystem>().UpdateUserInterface(this);
|
||||||
|
|
||||||
UpdateUserInterface();
|
|
||||||
|
|
||||||
Owner.EntityManager.EventBus.SubscribeEvent<GhostComponent.GhostReturnMessage>(EventSource.Local, this,
|
|
||||||
HandleGhostReturn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(float frameTime)
|
|
||||||
{
|
|
||||||
if (_bodyContainer.ContainedEntity != null &&
|
|
||||||
Powered)
|
|
||||||
{
|
|
||||||
_cloningProgress += frameTime;
|
|
||||||
_cloningProgress = MathHelper.Clamp(_cloningProgress, 0f, _cloningTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_cloningProgress >= _cloningTime &&
|
|
||||||
_bodyContainer.ContainedEntity != null &&
|
|
||||||
_capturedMind?.Session?.AttachedEntity == _bodyContainer.ContainedEntity &&
|
|
||||||
Powered)
|
|
||||||
{
|
|
||||||
_bodyContainer.Remove(_bodyContainer.ContainedEntity);
|
|
||||||
_capturedMind = null;
|
|
||||||
_cloningProgress = 0f;
|
|
||||||
|
|
||||||
_status = CloningPodStatus.Idle;
|
|
||||||
UpdateAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateUserInterface();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnRemove()
|
public override void OnRemove()
|
||||||
@@ -98,45 +67,17 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
UserInterface.OnReceiveMessage -= OnUiReceiveMessage;
|
UserInterface.OnReceiveMessage -= OnUiReceiveMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Owner.EntityManager.EventBus.UnsubscribeEvent<GhostComponent.GhostReturnMessage>(EventSource.Local, this);
|
|
||||||
|
|
||||||
base.OnRemove();
|
base.OnRemove();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateUserInterface()
|
|
||||||
{
|
|
||||||
if (!Powered) return;
|
|
||||||
|
|
||||||
UserInterface?.SetState(GetUserInterfaceState());
|
|
||||||
}
|
|
||||||
|
|
||||||
private CloningPodBoundUserInterfaceState GetUserInterfaceState()
|
|
||||||
{
|
|
||||||
var idToUser = EntitySystem.Get<CloningSystem>().GetIdToUser();
|
|
||||||
|
|
||||||
return new CloningPodBoundUserInterfaceState(idToUser, _cloningProgress,
|
|
||||||
(_status == CloningPodStatus.Cloning));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAppearance()
|
private void UpdateAppearance()
|
||||||
{
|
{
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||||
{
|
{
|
||||||
appearance.SetData(CloningPodVisuals.Status, _status);
|
appearance.SetData(CloningPodVisuals.Status, Status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!Powered ||
|
|
||||||
!eventArgs.User.TryGetComponent(out IActorComponent? actor))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserInterface?.Open(actor.playerSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
||||||
{
|
{
|
||||||
if (obj.Message is not CloningPodUiButtonPressedMessage message) return;
|
if (obj.Message is not CloningPodUiButtonPressedMessage message) return;
|
||||||
@@ -144,49 +85,60 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
switch (message.Button)
|
switch (message.Button)
|
||||||
{
|
{
|
||||||
case UiButton.Clone:
|
case UiButton.Clone:
|
||||||
if (message.ScanId == null) return;
|
if (message.ScanId == null || BodyContainer.ContainedEntity != null)
|
||||||
|
return;
|
||||||
|
|
||||||
var cloningSystem = EntitySystem.Get<CloningSystem>();
|
var cloningSystem = EntitySystem.Get<CloningSystem>();
|
||||||
|
|
||||||
if (_bodyContainer.ContainedEntity != null ||
|
if (!cloningSystem.Minds.TryGetValue(message.ScanId.Value, out var mind))
|
||||||
!cloningSystem.Minds.TryGetValue(message.ScanId.Value, out var mind))
|
|
||||||
{
|
{
|
||||||
return;
|
return; // ScanId is not in database
|
||||||
}
|
}
|
||||||
|
|
||||||
var dead =
|
if (cloningSystem.ClonesWaitingForMind.TryGetValue(mind, out var cloneUid))
|
||||||
mind.OwnedEntity != null &&
|
{
|
||||||
mind.OwnedEntity.TryGetComponent<IMobStateComponent>(out var state) &&
|
if (Owner.EntityManager.TryGetEntity(cloneUid, out var clone) &&
|
||||||
state.IsDead();
|
clone.TryGetComponent<IMobStateComponent>(out var cloneState) &&
|
||||||
if (!dead) return;
|
!cloneState.IsDead() &&
|
||||||
|
clone.TryGetComponent(out MindComponent? cloneMindComp) &&
|
||||||
|
(cloneMindComp.Mind == null || cloneMindComp.Mind == mind))
|
||||||
|
return; // Mind already has clone
|
||||||
|
|
||||||
|
cloningSystem.ClonesWaitingForMind.Remove(mind);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mind.OwnedEntity != null &&
|
||||||
|
mind.OwnedEntity.TryGetComponent<IMobStateComponent>(out var state) &&
|
||||||
|
!state.IsDead())
|
||||||
|
return; // Body controlled by mind is not dead
|
||||||
|
|
||||||
|
// TODO: Implement ClonerDNAEntry and get the profile appearance and name when scanned
|
||||||
|
if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client))
|
||||||
|
return;
|
||||||
|
|
||||||
var mob = Owner.EntityManager.SpawnEntity("HumanMob_Content", Owner.Transform.MapPosition);
|
var mob = Owner.EntityManager.SpawnEntity("HumanMob_Content", Owner.Transform.MapPosition);
|
||||||
var client = _playerManager.GetSessionByUserId(mind.UserId!.Value);
|
|
||||||
var profile = GetPlayerProfileAsync(client.UserId);
|
var profile = GetPlayerProfileAsync(client.UserId);
|
||||||
mob.GetComponent<HumanoidAppearanceComponent>().UpdateFromProfile(profile);
|
mob.GetComponent<HumanoidAppearanceComponent>().UpdateFromProfile(profile);
|
||||||
mob.Name = profile.Name;
|
mob.Name = profile.Name;
|
||||||
|
|
||||||
_bodyContainer.Insert(mob);
|
var cloneMindReturn = mob.AddComponent<BeingClonedComponent>();
|
||||||
_capturedMind = mind;
|
cloneMindReturn.Mind = mind;
|
||||||
|
cloneMindReturn.Parent = Owner.Uid;
|
||||||
|
|
||||||
_status = CloningPodStatus.NoMind;
|
BodyContainer.Insert(mob);
|
||||||
|
CapturedMind = mind;
|
||||||
|
cloningSystem.ClonesWaitingForMind.Add(mind, mob.Uid);
|
||||||
|
|
||||||
var acceptMessage = new AcceptCloningEui(mob);
|
UpdateStatus(CloningPodStatus.NoMind);
|
||||||
|
|
||||||
|
var acceptMessage = new AcceptCloningEui(mind);
|
||||||
_euiManager.OpenEui(acceptMessage, client);
|
_euiManager.OpenEui(acceptMessage, client);
|
||||||
|
|
||||||
UpdateAppearance();
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UiButton.Eject:
|
case UiButton.Eject:
|
||||||
if (_bodyContainer.ContainedEntity == null || _cloningProgress < _cloningTime) break;
|
Eject();
|
||||||
|
|
||||||
_bodyContainer.Remove(_bodyContainer.ContainedEntity!);
|
|
||||||
_capturedMind = null;
|
|
||||||
_cloningProgress = 0f;
|
|
||||||
_status = CloningPodStatus.Idle;
|
|
||||||
UpdateAppearance();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -194,21 +146,29 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Eject()
|
||||||
|
{
|
||||||
|
var entity = BodyContainer.ContainedEntity;
|
||||||
|
if (entity == null || CloningProgress < CloningTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entity.RemoveComponent<BeingClonedComponent>();
|
||||||
|
BodyContainer.Remove(entity!);
|
||||||
|
CapturedMind = null;
|
||||||
|
CloningProgress = 0f;
|
||||||
|
UpdateStatus(CloningPodStatus.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateStatus(CloningPodStatus status)
|
||||||
|
{
|
||||||
|
Status = status;
|
||||||
|
UpdateAppearance();
|
||||||
|
EntitySystem.Get<CloningSystem>().UpdateUserInterface(this);
|
||||||
|
}
|
||||||
|
|
||||||
private HumanoidCharacterProfile GetPlayerProfileAsync(NetUserId userId)
|
private HumanoidCharacterProfile GetPlayerProfileAsync(NetUserId userId)
|
||||||
{
|
{
|
||||||
return (HumanoidCharacterProfile) _prefsManager.GetPreferences(userId).SelectedCharacter;
|
return (HumanoidCharacterProfile) _prefsManager.GetPreferences(userId).SelectedCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleGhostReturn(GhostComponent.GhostReturnMessage message)
|
|
||||||
{
|
|
||||||
if (message.Sender == _capturedMind)
|
|
||||||
{
|
|
||||||
//Transfer the mind to the new mob
|
|
||||||
_capturedMind.TransferTo(_bodyContainer.ContainedEntity);
|
|
||||||
|
|
||||||
_status = CloningPodStatus.Cloning;
|
|
||||||
UpdateAppearance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ namespace Content.Server.GameObjects.Components.Mobs
|
|||||||
public void InternalAssignMind(Mind value)
|
public void InternalAssignMind(Mind value)
|
||||||
{
|
{
|
||||||
Mind = value;
|
Mind = value;
|
||||||
|
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new MindAddedMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Shutdown()
|
protected override void Shutdown()
|
||||||
@@ -156,4 +157,8 @@ namespace Content.Server.GameObjects.Components.Mobs
|
|||||||
public class MindRemovedMessage : EntityEventArgs
|
public class MindRemovedMessage : EntityEventArgs
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class MindAddedMessage : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#nullable enable
|
|
||||||
using Content.Server.Eui;
|
using Content.Server.Eui;
|
||||||
using Content.Server.Players;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Server.Mobs;
|
||||||
using Content.Shared.Eui;
|
using Content.Shared.Eui;
|
||||||
using Content.Shared.GameObjects.Components.Observer;
|
using Content.Shared.GameObjects.Components.Observer;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -9,28 +9,26 @@ namespace Content.Server.GameObjects.Components.Observer
|
|||||||
{
|
{
|
||||||
public class AcceptCloningEui : BaseEui
|
public class AcceptCloningEui : BaseEui
|
||||||
{
|
{
|
||||||
private readonly IEntity _newMob;
|
private readonly Mind _mind;
|
||||||
|
|
||||||
public AcceptCloningEui(IEntity newMob)
|
public AcceptCloningEui(Mind mind)
|
||||||
{
|
{
|
||||||
_newMob = newMob;
|
_mind = mind;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void HandleMessage(EuiMessageBase msg)
|
public override void HandleMessage(EuiMessageBase msg)
|
||||||
{
|
{
|
||||||
base.HandleMessage(msg);
|
base.HandleMessage(msg);
|
||||||
|
|
||||||
if (msg is not AcceptCloningChoiceMessage choice
|
if (msg is not AcceptCloningChoiceMessage choice ||
|
||||||
|| choice.Button == AcceptCloningUiButton.Deny
|
choice.Button == AcceptCloningUiButton.Deny ||
|
||||||
|| _newMob.Deleted)
|
!EntitySystem.TryGet<CloningSystem>(out var cloningSystem))
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mind = Player.ContentData()?.Mind;
|
cloningSystem.TransferMindToClone(_mind);
|
||||||
mind?.TransferTo(_newMob);
|
|
||||||
mind?.UnVisit();
|
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,13 +95,6 @@ namespace Content.Server.GameObjects.Components.Observer
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ReturnToCloneComponentMessage _:
|
|
||||||
|
|
||||||
if (Owner.TryGetComponent(out VisitingMindComponent? mind) && mind.Mind != null)
|
|
||||||
{
|
|
||||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new GhostReturnMessage(mind.Mind));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GhostWarpToLocationRequestMessage warp:
|
case GhostWarpToLocationRequestMessage warp:
|
||||||
{
|
{
|
||||||
if (session?.AttachedEntity != Owner)
|
if (session?.AttachedEntity != Owner)
|
||||||
@@ -191,15 +184,5 @@ namespace Content.Server.GameObjects.Components.Observer
|
|||||||
|
|
||||||
message.AddMarkup(Loc.GetString("Died [color=yellow]{0}[/color].", deathTimeInfo));
|
message.AddMarkup(Loc.GetString("Died [color=yellow]{0}[/color].", deathTimeInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GhostReturnMessage : EntityEventArgs
|
|
||||||
{
|
|
||||||
public GhostReturnMessage(Mind sender)
|
|
||||||
{
|
|
||||||
Sender = sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mind Sender { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,107 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components.Medical;
|
using Content.Server.GameObjects.Components.Medical;
|
||||||
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.Mobs;
|
using Content.Server.Mobs;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Interfaces.GameObjects.Components;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using static Content.Shared.GameObjects.Components.Medical.SharedCloningPodComponent;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.EntitySystems
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
{
|
{
|
||||||
internal sealed class CloningSystem : EntitySystem, IResettingEntitySystem
|
internal sealed class CloningSystem : EntitySystem, IResettingEntitySystem
|
||||||
{
|
{
|
||||||
|
public readonly Dictionary<int, Mind> Minds = new();
|
||||||
|
public readonly Dictionary<Mind, EntityUid> ClonesWaitingForMind = new();
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<CloningPodComponent, ActivateInWorldMessage>(HandleActivate);
|
||||||
|
SubscribeLocalEvent<BeingClonedComponent, MindAddedMessage>(HandleMindAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
|
||||||
|
UnsubscribeLocalEvent<CloningPodComponent, ActivateInWorldMessage>(HandleActivate);
|
||||||
|
UnsubscribeLocalEvent<BeingClonedComponent, MindAddedMessage>(HandleMindAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void TransferMindToClone(Mind mind)
|
||||||
|
{
|
||||||
|
if (!ClonesWaitingForMind.TryGetValue(mind, out var entityUid) ||
|
||||||
|
!EntityManager.TryGetEntity(entityUid, out var entity) ||
|
||||||
|
!entity.TryGetComponent(out MindComponent? mindComp) ||
|
||||||
|
mindComp.Mind != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mind?.TransferTo(entity);
|
||||||
|
mind?.UnVisit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleActivate(EntityUid uid, CloningPodComponent component, ActivateInWorldMessage args)
|
||||||
|
{
|
||||||
|
if (!component.Powered ||
|
||||||
|
!args.User.TryGetComponent(out IActorComponent? actor))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.UserInterface?.Open(actor.playerSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleMindAdded(EntityUid uid, BeingClonedComponent component, MindAddedMessage message)
|
||||||
|
{
|
||||||
|
if (component.Parent == EntityUid.Invalid ||
|
||||||
|
!EntityManager.TryGetEntity(component.Parent, out var parent) ||
|
||||||
|
!parent.TryGetComponent<CloningPodComponent>(out var cloningPodComponent) ||
|
||||||
|
component.Owner != cloningPodComponent.BodyContainer?.ContainedEntity)
|
||||||
|
{
|
||||||
|
component.Owner.RemoveComponent<BeingClonedComponent>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cloningPodComponent.UpdateStatus(CloningPodStatus.Cloning);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
foreach (var comp in ComponentManager.EntityQuery<CloningPodComponent>(true))
|
foreach (var (cloning, power) in ComponentManager.EntityQuery<CloningPodComponent, PowerReceiverComponent>(true))
|
||||||
{
|
{
|
||||||
comp.Update(frameTime);
|
if (!power.Powered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cloning.BodyContainer.ContainedEntity != null)
|
||||||
|
{
|
||||||
|
cloning.CloningProgress += frameTime;
|
||||||
|
cloning.CloningProgress = MathHelper.Clamp(cloning.CloningProgress, 0f, cloning.CloningTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cloning.CapturedMind?.Session?.AttachedEntity == cloning.BodyContainer.ContainedEntity)
|
||||||
|
{
|
||||||
|
cloning.Eject();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateUserInterface(cloning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly Dictionary<int, Mind> Minds = new();
|
public void UpdateUserInterface(CloningPodComponent comp)
|
||||||
|
{
|
||||||
|
var idToUser = GetIdToUser();
|
||||||
|
comp.UserInterface?.SetState(
|
||||||
|
new CloningPodBoundUserInterfaceState(
|
||||||
|
idToUser,
|
||||||
|
comp.CloningProgress,
|
||||||
|
comp.Status == CloningPodStatus.Cloning));
|
||||||
|
}
|
||||||
|
|
||||||
public void AddToDnaScans(Mind mind)
|
public void AddToDnaScans(Mind mind)
|
||||||
{
|
{
|
||||||
@@ -40,6 +124,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
Minds.Clear();
|
Minds.Clear();
|
||||||
|
ClonesWaitingForMind.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,13 +81,6 @@ namespace Content.Shared.GameObjects.Components.Observer
|
|||||||
Directed = true;
|
Directed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public class ReturnToCloneComponentMessage : ComponentMessage
|
|
||||||
{
|
|
||||||
public ReturnToCloneComponentMessage() => Directed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user