@@ -0,0 +1,30 @@
|
||||
using Content.Shared.Changeling.Components;
|
||||
using Content.Shared.Changeling.Systems;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Changeling.Systems;
|
||||
|
||||
public sealed class ChangelingIdentitySystem : SharedChangelingIdentitySystem
|
||||
{
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ChangelingIdentityComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
||||
}
|
||||
|
||||
private void OnAfterAutoHandleState(Entity<ChangelingIdentityComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
UpdateUi(ent);
|
||||
}
|
||||
|
||||
public void UpdateUi(EntityUid uid)
|
||||
{
|
||||
if (_ui.TryGetOpenUi(uid, ChangelingTransformUiKey.Key, out var bui))
|
||||
{
|
||||
bui.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Changeling.Transform;
|
||||
namespace Content.Client.Changeling.UI;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ChangelingTransformBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
|
||||
@@ -16,16 +16,16 @@ public sealed partial class ChangelingTransformBoundUserInterface(EntityUid owne
|
||||
_window = this.CreateWindow<ChangelingTransformMenu>();
|
||||
|
||||
_window.OnIdentitySelect += SendIdentitySelect;
|
||||
|
||||
_window.Update(Owner);
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
public override void Update()
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (state is not ChangelingTransformBoundUserInterfaceState current)
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_window?.UpdateState(current);
|
||||
_window.Update(Owner);
|
||||
}
|
||||
|
||||
public void SendIdentitySelect(NetEntity identityId)
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Changeling.Systems;
|
||||
using Content.Shared.Changeling.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Changeling.Transform;
|
||||
namespace Content.Client.Changeling.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ChangelingTransformMenu : RadialMenu
|
||||
@@ -19,13 +19,15 @@ public sealed partial class ChangelingTransformMenu : RadialMenu
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public void UpdateState(ChangelingTransformBoundUserInterfaceState state)
|
||||
public void Update(EntityUid uid)
|
||||
{
|
||||
Main.DisposeAllChildren();
|
||||
foreach (var identity in state.Identites)
|
||||
{
|
||||
var identityUid = _entity.GetEntity(identity);
|
||||
|
||||
if (!_entity.TryGetComponent<ChangelingIdentityComponent>(uid, out var identityComp))
|
||||
return;
|
||||
|
||||
foreach (var identityUid in identityComp.ConsumedIdentities)
|
||||
{
|
||||
if (!_entity.TryGetComponent<MetaDataComponent>(identityUid, out var metadata))
|
||||
continue;
|
||||
|
||||
@@ -48,7 +50,7 @@ public sealed partial class ChangelingTransformMenu : RadialMenu
|
||||
entView.SetEntity(identityUid);
|
||||
button.OnButtonUp += _ =>
|
||||
{
|
||||
OnIdentitySelect?.Invoke(identity);
|
||||
OnIdentitySelect?.Invoke(_entity.GetNetEntity(identityUid));
|
||||
Close();
|
||||
};
|
||||
button.AddChild(entView);
|
||||
@@ -0,0 +1,5 @@
|
||||
using Content.Shared.Changeling.Systems;
|
||||
|
||||
namespace Content.Server.Changeling.Systems;
|
||||
|
||||
public sealed class ChangelingIdentitySystem : SharedChangelingIdentitySystem;
|
||||
@@ -8,7 +8,7 @@ namespace Content.Shared.Changeling.Components;
|
||||
/// The storage component for Changelings, it handles the link between a changeling and its consumed identities
|
||||
/// that exist on a paused map.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(raiseAfterAutoHandleState: true)]
|
||||
public sealed partial class ChangelingIdentityComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class ChangelingDevourSystem : EntitySystem
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly ChangelingIdentitySystem _changelingIdentitySystem = default!;
|
||||
[Dependency] private readonly SharedChangelingIdentitySystem _changelingIdentitySystem = default!;
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
|
||||
@@ -14,20 +14,8 @@ public sealed class ChangelingTransformIdentitySelectMessage(NetEntity targetIde
|
||||
public readonly NetEntity TargetIdentity = targetIdentity;
|
||||
}
|
||||
|
||||
// TODO: Replace with component states.
|
||||
// We are already networking the ChangelingIdentityComponent, which contains all this information,
|
||||
// so we can just read it from them from the component and update the UI in an AfterAuotHandleState subscription.
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ChangelingTransformBoundUserInterfaceState(List<NetEntity> identities) : BoundUserInterfaceState
|
||||
{
|
||||
/// <summary>
|
||||
/// The uids of the cloned identities.
|
||||
/// </summary>
|
||||
public readonly List<NetEntity> Identites = identities;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum TransformUI : byte
|
||||
public enum ChangelingTransformUiKey : byte
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public sealed partial class ChangelingTransformSystem : EntitySystem
|
||||
_actionsSystem.AddAction(ent, ref ent.Comp.ChangelingTransformActionEntity, ent.Comp.ChangelingTransformAction);
|
||||
|
||||
var userInterfaceComp = EnsureComp<UserInterfaceComponent>(ent);
|
||||
_uiSystem.SetUi((ent, userInterfaceComp), TransformUI.Key, new InterfaceData(ChangelingBuiXmlGeneratedName));
|
||||
_uiSystem.SetUi((ent, userInterfaceComp), ChangelingTransformUiKey.Key, new InterfaceData(ChangelingBuiXmlGeneratedName));
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<ChangelingTransformComponent> ent, ref ComponentShutdown args)
|
||||
@@ -64,18 +64,9 @@ public sealed partial class ChangelingTransformSystem : EntitySystem
|
||||
if (!TryComp<ChangelingIdentityComponent>(ent, out var userIdentity))
|
||||
return;
|
||||
|
||||
if (!_uiSystem.IsUiOpen((ent, userInterfaceComp), TransformUI.Key, args.Performer))
|
||||
if (!_uiSystem.IsUiOpen((ent, userInterfaceComp), ChangelingTransformUiKey.Key, args.Performer))
|
||||
{
|
||||
_uiSystem.OpenUi((ent, userInterfaceComp), TransformUI.Key, args.Performer);
|
||||
|
||||
var identityData = new List<NetEntity>();
|
||||
|
||||
foreach (var consumedIdentity in userIdentity.ConsumedIdentities)
|
||||
{
|
||||
identityData.Add(GetNetEntity(consumedIdentity));
|
||||
}
|
||||
|
||||
_uiSystem.SetUiState((ent, userInterfaceComp), TransformUI.Key, new ChangelingTransformBoundUserInterfaceState(identityData));
|
||||
_uiSystem.OpenUi((ent, userInterfaceComp), ChangelingTransformUiKey.Key, args.Performer);
|
||||
} //TODO: Can add a Else here with TransformInto and CloseUI to make a quick switch,
|
||||
// issue right now is that Radials cover the Action buttons so clicking the action closes the UI (due to clicking off a radial causing it to close, even with UI)
|
||||
// but pressing the number does.
|
||||
@@ -108,7 +99,7 @@ public sealed partial class ChangelingTransformSystem : EntitySystem
|
||||
else
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(ent.Owner):player} begun an attempt to transform into \"{Name(targetIdentity)}\"");
|
||||
|
||||
var result = _doAfterSystem.TryStartDoAfter(new DoAfterArgs(
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(
|
||||
EntityManager,
|
||||
ent,
|
||||
ent.Comp.TransformWindup,
|
||||
@@ -127,7 +118,7 @@ public sealed partial class ChangelingTransformSystem : EntitySystem
|
||||
private void OnTransformSelected(Entity<ChangelingTransformComponent> ent,
|
||||
ref ChangelingTransformIdentitySelectMessage args)
|
||||
{
|
||||
_uiSystem.CloseUi(ent.Owner, TransformUI.Key, ent);
|
||||
_uiSystem.CloseUi(ent.Owner, ChangelingTransformUiKey.Key, ent);
|
||||
|
||||
if (!TryGetEntity(args.TargetIdentity, out var targetIdentity))
|
||||
return;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Content.Shared.Changeling.Components;
|
||||
using Content.Shared.Cloning;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
@@ -12,7 +11,7 @@ using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Changeling.Systems;
|
||||
|
||||
public sealed class ChangelingIdentitySystem : EntitySystem
|
||||
public abstract class SharedChangelingIdentitySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
@@ -32,22 +31,19 @@ public sealed class ChangelingIdentitySystem : EntitySystem
|
||||
|
||||
SubscribeLocalEvent<ChangelingIdentityComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<ChangelingIdentityComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<ChangelingIdentityComponent, MindAddedMessage>(OnMindAdded);
|
||||
SubscribeLocalEvent<ChangelingIdentityComponent, MindRemovedMessage>(OnMindRemoved);
|
||||
SubscribeLocalEvent<ChangelingIdentityComponent, PlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<ChangelingIdentityComponent, PlayerDetachedEvent>(OnPlayerDetached);
|
||||
SubscribeLocalEvent<ChangelingStoredIdentityComponent, ComponentRemove>(OnStoredRemove);
|
||||
}
|
||||
|
||||
private void OnMindAdded(Entity<ChangelingIdentityComponent> ent, ref MindAddedMessage args)
|
||||
private void OnPlayerAttached(Entity<ChangelingIdentityComponent> ent, ref PlayerAttachedEvent args)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(args.Container.Owner, out var actor))
|
||||
return;
|
||||
|
||||
HandOverPvsOverride(actor.PlayerSession, ent.Comp);
|
||||
HandOverPvsOverride(ent, args.Player);
|
||||
}
|
||||
|
||||
private void OnMindRemoved(Entity<ChangelingIdentityComponent> ent, ref MindRemovedMessage args)
|
||||
private void OnPlayerDetached(Entity<ChangelingIdentityComponent> ent, ref PlayerDetachedEvent args)
|
||||
{
|
||||
CleanupPvsOverride(ent, args.Container.Owner);
|
||||
CleanupPvsOverride(ent, args.Player);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<ChangelingIdentityComponent> ent, ref MapInitEvent args)
|
||||
@@ -59,7 +55,8 @@ public sealed class ChangelingIdentitySystem : EntitySystem
|
||||
|
||||
private void OnShutdown(Entity<ChangelingIdentityComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
CleanupPvsOverride(ent, ent.Owner);
|
||||
if (TryComp<ActorComponent>(ent, out var actor))
|
||||
CleanupPvsOverride(ent, actor.PlayerSession);
|
||||
CleanupChangelingNullspaceIdentities(ent);
|
||||
}
|
||||
|
||||
@@ -107,66 +104,63 @@ public sealed class ChangelingIdentitySystem : EntitySystem
|
||||
// Movercontrollers and mob collisions are currently being calculated even for paused entities.
|
||||
// Spawning all of them in the same spot causes severe performance problems.
|
||||
// Cryopods and Polymorph have the same problem.
|
||||
var mob = Spawn(speciesPrototype.Prototype, new MapCoordinates(new Vector2(2 * _numberOfStoredIdentities++, 0), PausedMapId!.Value));
|
||||
var clone = Spawn(speciesPrototype.Prototype, new MapCoordinates(new Vector2(2 * _numberOfStoredIdentities++, 0), PausedMapId!.Value));
|
||||
|
||||
var storedIdentity = EnsureComp<ChangelingStoredIdentityComponent>(mob);
|
||||
var storedIdentity = EnsureComp<ChangelingStoredIdentityComponent>(clone);
|
||||
storedIdentity.OriginalEntity = target; // TODO: network this once we have WeakEntityReference or the autonetworking source gen is fixed
|
||||
|
||||
if (TryComp<ActorComponent>(target, out var actor))
|
||||
storedIdentity.OriginalSession = actor.PlayerSession;
|
||||
|
||||
_humanoidSystem.CloneAppearance(target, mob);
|
||||
_cloningSystem.CloneComponents(target, mob, settings);
|
||||
_humanoidSystem.CloneAppearance(target, clone);
|
||||
_cloningSystem.CloneComponents(target, clone, settings);
|
||||
|
||||
var targetName = _nameMod.GetBaseName(target);
|
||||
_metaSystem.SetEntityName(mob, targetName);
|
||||
ent.Comp.ConsumedIdentities.Add(mob);
|
||||
_metaSystem.SetEntityName(clone, targetName);
|
||||
ent.Comp.ConsumedIdentities.Add(clone);
|
||||
|
||||
Dirty(ent);
|
||||
HandlePvsOverride(ent, mob);
|
||||
HandlePvsOverride(ent, clone);
|
||||
|
||||
return mob;
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple helper to add a PVS override to a Nullspace Identity
|
||||
/// Simple helper to add a PVS override to a nullspace identity.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="target"></param>
|
||||
private void HandlePvsOverride(EntityUid uid, EntityUid target)
|
||||
/// <param name="uid">The actor that should get the override.</param>
|
||||
/// <param name="identity">The identity stored in nullspace.</param>
|
||||
private void HandlePvsOverride(EntityUid uid, EntityUid identity)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(uid, out var actor))
|
||||
return;
|
||||
|
||||
_pvsOverrideSystem.AddSessionOverride(target, actor.PlayerSession);
|
||||
_pvsOverrideSystem.AddSessionOverride(identity, actor.PlayerSession);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup all Pvs Overrides for the owner of the ChangelingIdentity
|
||||
/// Cleanup all PVS overrides for the owner of the ChangelingIdentity
|
||||
/// </summary>
|
||||
/// <param name="ent">the Changeling itself</param>
|
||||
/// <param name="entityUid">Who specifically to cleanup from, usually just the same owner, but in the case of a mindswap we want to clean up the victim</param>
|
||||
private void CleanupPvsOverride(Entity<ChangelingIdentityComponent> ent, EntityUid entityUid)
|
||||
/// <param name="ent">The changeling storing the identities.</param>
|
||||
/// <param name="entityUid"The session you wish to remove the overrides from.</param>
|
||||
private void CleanupPvsOverride(Entity<ChangelingIdentityComponent> ent, ICommonSession session)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(entityUid, out var actor))
|
||||
return;
|
||||
|
||||
foreach (var identity in ent.Comp.ConsumedIdentities)
|
||||
{
|
||||
_pvsOverrideSystem.RemoveSessionOverride(identity, actor.PlayerSession);
|
||||
_pvsOverrideSystem.RemoveSessionOverride(identity, session);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inform another Session of the entities stored for Transformation
|
||||
/// Inform another session of the entities stored for transformation.
|
||||
/// </summary>
|
||||
/// <param name="session">The Session you wish to inform</param>
|
||||
/// <param name="comp">The Target storage of identities</param>
|
||||
public void HandOverPvsOverride(ICommonSession session, ChangelingIdentityComponent comp)
|
||||
/// <param name="ent">The changeling storing the identities.</param>
|
||||
/// <param name="session">The session you wish to inform.</param>
|
||||
public void HandOverPvsOverride(Entity<ChangelingIdentityComponent> ent, ICommonSession session)
|
||||
{
|
||||
foreach (var entity in comp.ConsumedIdentities)
|
||||
foreach (var identity in ent.Comp.ConsumedIdentities)
|
||||
{
|
||||
_pvsOverrideSystem.AddSessionOverride(entity, session);
|
||||
_pvsOverrideSystem.AddSessionOverride(identity, session);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user