Move character preview handling into a specialized control (#41252)

* Move character preview handling into a specialized control

Co-authored-by: Quantum-cross <7065792+Quantum-cross@users.noreply.github.com>

* Restore job name that I accidentally removed from character picker buttons

* Just resolve dependencies the standard way

---------

Co-authored-by: Quantum-cross <7065792+Quantum-cross@users.noreply.github.com>
Co-authored-by: Janet Blackquill <uhhadd@gmail.com>
This commit is contained in:
Absotively 2026-01-26 11:18:29 -07:00 committed by Coryler
parent e3eb8083e8
commit abb13de3dd
10 changed files with 299 additions and 266 deletions

View File

@ -37,7 +37,6 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly JobRequirementsManager _requirements = default!;
[Dependency] private readonly MarkingManager _markings = default!;
[UISystemDependency] private readonly VisualBodySystem _visualBody = default!;
[UISystemDependency] private readonly ClientInventorySystem _inventory = default!;
[UISystemDependency] private readonly StationSpawningSystem _spawn = default!;
[UISystemDependency] private readonly GuidebookSystem _guide = default!;
@ -181,13 +180,12 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
if (character is not HumanoidCharacterProfile humanoid)
{
PreviewPanel.SetSprite(EntityUid.Invalid);
PreviewPanel.ProfilePreviewSpriteView.ClearPreview();
PreviewPanel.SetSummaryText(string.Empty);
return;
}
var dummy = LoadProfileEntity(humanoid, null, true);
PreviewPanel.SetSprite(dummy);
PreviewPanel.ProfilePreviewSpriteView.LoadPreview(humanoid);
PreviewPanel.SetSummaryText(humanoid.Summary);
}
@ -324,175 +322,4 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
return (_characterSetup, _profileEditor);
}
#region Helpers
/// <summary>
/// Applies the highest priority job's clothes to the dummy.
/// </summary>
public void GiveDummyJobClothesLoadout(EntityUid dummy, JobPrototype? jobProto, HumanoidCharacterProfile profile)
{
var job = jobProto ?? GetPreferredJob(profile);
GiveDummyJobClothes(dummy, profile, job);
if (_prototypeManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(job.ID)))
{
var loadout = profile.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), _playerManager.LocalSession, profile.Species, EntityManager, _prototypeManager);
GiveDummyLoadout(dummy, loadout);
}
}
/// <summary>
/// Gets the highest priority job for the profile.
/// </summary>
public JobPrototype GetPreferredJob(HumanoidCharacterProfile profile)
{
var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key;
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract (what is resharper smoking?)
return _prototypeManager.Index<JobPrototype>(highPriorityJob.Id ?? SharedGameTicker.FallbackOverflowJob);
}
public void GiveDummyLoadout(EntityUid uid, RoleLoadout? roleLoadout)
{
if (roleLoadout == null)
return;
foreach (var group in roleLoadout.SelectedLoadouts.Values)
{
foreach (var loadout in group)
{
if (!_prototypeManager.Resolve(loadout.Prototype, out var loadoutProto))
continue;
_spawn.EquipStartingGear(uid, loadoutProto);
}
}
}
/// <summary>
/// Applies the specified job's clothes to the dummy.
/// </summary>
public void GiveDummyJobClothes(EntityUid dummy, HumanoidCharacterProfile profile, JobPrototype job)
{
if (!_inventory.TryGetSlots(dummy, out var slots))
return;
// Apply loadout
if (profile.Loadouts.TryGetValue(job.ID, out var jobLoadout))
{
foreach (var loadouts in jobLoadout.SelectedLoadouts.Values)
{
foreach (var loadout in loadouts)
{
if (!_prototypeManager.Resolve(loadout.Prototype, out var loadoutProto))
continue;
// TODO: Need some way to apply starting gear to an entity and replace existing stuff coz holy fucking shit dude.
foreach (var slot in slots)
{
// Try startinggear first
if (_prototypeManager.Resolve(loadoutProto.StartingGear, out var loadoutGear))
{
var itemType = ((IEquipmentLoadout) loadoutGear).GetGear(slot.Name);
if (_inventory.TryUnequip(dummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
{
EntityManager.DeleteEntity(unequippedItem.Value);
}
if (itemType != string.Empty)
{
var item = EntityManager.SpawnEntity(itemType, MapCoordinates.Nullspace);
_inventory.TryEquip(dummy, item, slot.Name, true, true);
}
}
else
{
var itemType = ((IEquipmentLoadout) loadoutProto).GetGear(slot.Name);
if (_inventory.TryUnequip(dummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
{
EntityManager.DeleteEntity(unequippedItem.Value);
}
if (itemType != string.Empty)
{
var item = EntityManager.SpawnEntity(itemType, MapCoordinates.Nullspace);
_inventory.TryEquip(dummy, item, slot.Name, true, true);
}
}
}
}
}
}
if (!_prototypeManager.Resolve(job.StartingGear, out var gear))
return;
foreach (var slot in slots)
{
var itemType = ((IEquipmentLoadout) gear).GetGear(slot.Name);
if (_inventory.TryUnequip(dummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
{
EntityManager.DeleteEntity(unequippedItem.Value);
}
if (itemType != string.Empty)
{
var item = EntityManager.SpawnEntity(itemType, MapCoordinates.Nullspace);
_inventory.TryEquip(dummy, item, slot.Name, true, true);
}
}
}
/// <summary>
/// Loads the profile onto a dummy entity.
/// </summary>
public EntityUid LoadProfileEntity(HumanoidCharacterProfile? humanoid, JobPrototype? job, bool jobClothes)
{
EntityUid dummyEnt;
EntProtoId? previewEntity = null;
if (humanoid != null && jobClothes)
{
job ??= GetPreferredJob(humanoid);
previewEntity = job.JobPreviewEntity ?? (EntProtoId?)job?.JobEntity;
}
if (previewEntity != null)
{
// Special type like borg or AI, do not spawn a human just spawn the entity.
dummyEnt = EntityManager.SpawnEntity(previewEntity, MapCoordinates.Nullspace);
return dummyEnt;
}
else if (humanoid is not null)
{
var dummy = _prototypeManager.Index(humanoid.Species).DollPrototype;
dummyEnt = EntityManager.SpawnEntity(dummy, MapCoordinates.Nullspace);
_visualBody.ApplyProfileTo(dummyEnt, humanoid);
}
else
{
dummyEnt = EntityManager.SpawnEntity(_prototypeManager.Index(HumanoidCharacterProfile.DefaultSpecies).DollPrototype, MapCoordinates.Nullspace);
}
if (humanoid != null && jobClothes)
{
DebugTools.Assert(job != null);
GiveDummyJobClothes(dummyEnt, humanoid, job);
if (_prototypeManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(job.ID)))
{
var loadout = humanoid.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), _playerManager.LocalSession, humanoid.Species, EntityManager, _prototypeManager);
GiveDummyLoadout(dummyEnt, loadout);
}
}
return dummyEnt;
}
#endregion
}

View File

@ -1,15 +1,16 @@
<ContainerButton xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:profile="clr-namespace:Content.Client.Lobby.UI.ProfileEditorControls"
xmlns:style="clr-namespace:Content.Client.Stylesheets">
<BoxContainer Orientation="Horizontal"
HorizontalExpand="True"
SeparationOverride="0"
Name="InternalHBox">
<SpriteView Scale="2 2"
Margin="0 4 4 4"
OverrideDirection="South"
Name="View"
SetSize="64 64"/>
<profile:ProfilePreviewSpriteView Scale="2 2"
Margin="0 4 4 4"
OverrideDirection="South"
Name="View"
SetSize="64 64"/>
<Label Name="DescriptionLabel"
ClipText="True"
HorizontalExpand="True"/>

View File

@ -10,6 +10,7 @@ using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Client.Lobby.UI;
@ -20,37 +21,28 @@ namespace Content.Client.Lobby.UI;
[GenerateTypedNameReferences]
public sealed partial class CharacterPickerButton : ContainerButton
{
private IEntityManager _entManager;
private EntityUid _previewDummy;
/// <summary>
/// Invoked if we should delete the attached character
/// </summary>
public event Action? OnDeletePressed;
public CharacterPickerButton(
IEntityManager entityManager,
IPrototypeManager prototypeManager,
ISharedPlayerManager playerMan,
ButtonGroup group,
ICharacterProfile profile,
bool isSelected)
{
RobustXamlLoader.Load(this);
_entManager = entityManager;
AddStyleClass(StyleClassButton);
ToggleMode = true;
Group = group;
var description = profile.Name;
if (profile is not HumanoidCharacterProfile humanoid)
View.LoadPreview(profile);
if (profile is HumanoidCharacterProfile humanoid)
{
_previewDummy = entityManager.SpawnEntity(prototypeManager.Index<SpeciesPrototype>(HumanoidCharacterProfile.DefaultSpecies).DollPrototype, MapCoordinates.Nullspace);
}
else
{
_previewDummy = UserInterfaceManager.GetUIController<LobbyUIController>()
.LoadProfileEntity(humanoid, null, true);
var highPriorityJob = humanoid.JobPriorities.SingleOrDefault(p => p.Value == JobPriority.High).Key;
if (highPriorityJob != default)
@ -63,7 +55,6 @@ public sealed partial class CharacterPickerButton : ContainerButton
Pressed = isSelected;
DeleteButton.Visible = !isSelected;
View.SetEntity(_previewDummy);
DescriptionLabel.Text = description;
ConfirmDeleteButton.OnPressed += _ =>
@ -79,14 +70,4 @@ public sealed partial class CharacterPickerButton : ContainerButton
ConfirmDeleteButton.Visible = true;
};
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_entManager.DeleteEntity(_previewDummy);
_previewDummy = default;
}
}

View File

@ -11,6 +11,7 @@ using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Client.Lobby.UI
@ -22,10 +23,10 @@ namespace Content.Client.Lobby.UI
public sealed partial class CharacterSetupGui : Control
{
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _protomanager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
private readonly Button _createNewCharacterButton;
@ -96,8 +97,8 @@ namespace Content.Client.Lobby.UI
continue;
// End DeltaV
numberOfFullSlots++;
var characterPickerButton = new CharacterPickerButton(_entManager,
_protomanager,
var characterPickerButton = new CharacterPickerButton(_protomanager,
_playerManager,
characterButtonsGroup,
character,
slot == selectedSlot);

View File

@ -4,6 +4,7 @@
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns:ui="clr-namespace:Content.Client.Lobby.UI"
xmlns:traits="clr-namespace:Content.Client._DV.Traits.UI"
xmlns:profile="clr-namespace:Content.Client.Lobby.UI.ProfileEditorControls"
HorizontalExpand="True">
<!-- Left side -->
<BoxContainer Orientation="Vertical" Margin="10 10 10 10" HorizontalExpand="True">
@ -146,7 +147,7 @@
</BoxContainer>
<!-- Right side -->
<BoxContainer Orientation="Vertical" VerticalExpand="True" VerticalAlignment="Center">
<SpriteView Name="SpriteView" Scale="8 8" Margin="4" SizeFlagsStretchRatio="1" />
<profile:ProfilePreviewSpriteView Name="SpriteView" Scale="8 8" Margin="4" SizeFlagsStretchRatio="1" />
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 5">
<Button Name="SpriteRotateLeft" Text="◀" StyleClasses="OpenRight" />
<cc:VSeparator Margin="2 0 3 0" />

View File

@ -79,11 +79,6 @@ namespace Content.Client.Lobby.UI
/// </summary>
public event Action? Save;
/// <summary>
/// Entity used for the profile editor preview
/// </summary>
public EntityUid PreviewDummy;
/// <summary>
/// Temporary override of their selected job, used to preview roles.
/// </summary>
@ -743,15 +738,10 @@ namespace Content.Client.Lobby.UI
/// </remarks>
private void ReloadPreview()
{
_entManager.DeleteEntity(PreviewDummy);
PreviewDummy = EntityUid.Invalid;
if (Profile == null || !_prototypeManager.HasIndex(Profile.Species))
if (Profile == null)
return;
PreviewDummy = _controller.LoadProfileEntity(Profile, JobOverride, ShowClothes.Pressed);
SpriteView.SetEntity(PreviewDummy);
_entManager.System<MetaDataSystem>().SetEntityName(PreviewDummy, Profile.Name);
SpriteView.LoadPreview(Profile, JobOverride, ShowClothes.Pressed);
// Check and set the dirty flag to enable the save/reset buttons as appropriate.
SetDirty();
@ -809,16 +799,15 @@ namespace Content.Client.Lobby.UI
}
}
/// <summary>
/// A slim reload that only updates the entity itself and not any of the job entities, etc.
/// </summary>
private void ReloadProfilePreview()
{
if (Profile == null || !_entManager.EntityExists(PreviewDummy))
if (Profile == null)
return;
_entManager.System<SharedVisualBodySystem>().ApplyProfileTo(PreviewDummy, Profile);
SpriteView.ReloadProfilePreview(Profile);
// Check and set the dirty flag to enable the save/reset buttons as appropriate.
SetDirty();
@ -1184,13 +1173,6 @@ namespace Content.Client.Lobby.UI
ReloadPreview();
}
protected override void ExitedTree()
{
base.ExitedTree();
_entManager.DeleteEntity(PreviewDummy);
PreviewDummy = EntityUid.Invalid;
}
private void SetAge(int newAge)
{
Profile = Profile?.WithAge(newAge);
@ -1252,7 +1234,7 @@ namespace Content.Client.Lobby.UI
if (!IsDirty)
return;
_entManager.System<MetaDataSystem>().SetEntityName(PreviewDummy, newName);
SpriteView.SetName(newName);
}
// Begin CD - Character Records
@ -1503,7 +1485,7 @@ namespace Content.Client.Lobby.UI
// I tried disabling the button but it looks sorta goofy as it only takes a frame or two to save
_imaging = true;
await _entManager.System<ContentSpriteSystem>().Export(PreviewDummy, dir, includeId: false);
await _entManager.System<ContentSpriteSystem>().Export(SpriteView.PreviewDummy, dir, includeId: false);
_imaging = false;
}

View File

@ -1,7 +1,8 @@
<Control
xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:profile="clr-namespace:Content.Client.Lobby.UI.ProfileEditorControls">
<BoxContainer Name="VBox" Orientation="Vertical">
<controls:NanoHeading Name="Header" Text="{Loc 'lobby-character-preview-panel-header'}">
@ -10,7 +11,12 @@
Visible="False">
<Label Name="Summary" HorizontalAlignment="Center" Margin="3 3"/>
<BoxContainer Name="ViewBox" Orientation="Horizontal" HorizontalAlignment="Center">
<profile:ProfilePreviewSpriteView Name="ProfilePreviewSpriteView"
OverrideDirection="South"
Scale="4 4"
MaxSize="112 112"
Stretch="Fill"
Access="Public" />
</BoxContainer>
<controls:VSpacer/>
<Button Name="CharacterSetup" Text="{Loc 'lobby-character-preview-panel-character-setup-button'}"

View File

@ -4,18 +4,16 @@ using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Client.Lobby.UI;
[GenerateTypedNameReferences]
public sealed partial class LobbyCharacterPreviewPanel : Control
{
[Dependency] private readonly IEntityManager _entManager = default!;
public Button CharacterSetupButton => CharacterSetup;
private EntityUid? _previewDummy;
public LobbyCharacterPreviewPanel()
{
RobustXamlLoader.Load(this);
@ -32,32 +30,4 @@ public sealed partial class LobbyCharacterPreviewPanel : Control
{
Summary.Text = value;
}
public void SetSprite(EntityUid uid)
{
if (_previewDummy != null)
{
_entManager.DeleteEntity(_previewDummy);
}
_previewDummy = uid;
ViewBox.RemoveAllChildren();
var spriteView = new SpriteView
{
OverrideDirection = Direction.South,
Scale = new Vector2(4f, 4f),
MaxSize = new Vector2(112, 112),
Stretch = SpriteView.StretchMode.Fill,
};
spriteView.SetEntity(uid);
ViewBox.AddChild(spriteView);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_entManager.DeleteEntity(_previewDummy);
_previewDummy = null;
}
}

View File

@ -0,0 +1,182 @@
using System.Linq;
using Content.Client.Humanoid;
using Content.Client.Station;
using Content.Shared.Body;
using Content.Shared.Clothing;
using Content.Shared.GameTicking;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Inventory;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.Lobby.UI.ProfileEditorControls;
public sealed partial class ProfilePreviewSpriteView
{
/// <summary>
/// A slim reload that only updates the entity itself and not any of the job entities, etc.
/// </summary>
private void ReloadHumanoidEntity(HumanoidCharacterProfile humanoid)
{
if (!EntMan.EntityExists(PreviewDummy) ||
!EntMan.HasComponent<VisualBodyComponent>(PreviewDummy))
return;
EntMan.System<SharedVisualBodySystem>().ApplyProfileTo(PreviewDummy, humanoid);
}
/// <summary>
/// Loads the profile onto a dummy entity.
/// </summary>
private void LoadHumanoidEntity(HumanoidCharacterProfile? humanoid, JobPrototype? job, bool jobClothes)
{
EntProtoId? previewEntity = null;
if (humanoid != null && jobClothes)
{
job ??= GetPreferredJob(humanoid);
previewEntity = job.JobPreviewEntity ?? (EntProtoId?)job?.JobEntity;
}
if (previewEntity != null)
{
// Special type like borg or AI, do not spawn a human just spawn the entity.
PreviewDummy = EntMan.SpawnEntity(previewEntity, MapCoordinates.Nullspace);
}
else if (humanoid is not null)
{
var dummy = _prototypeManager.Index(humanoid.Species).DollPrototype;
PreviewDummy = EntMan.SpawnEntity(dummy, MapCoordinates.Nullspace);
EntMan.System<SharedVisualBodySystem>().ApplyProfileTo(PreviewDummy, humanoid);
}
else
{
PreviewDummy = EntMan.SpawnEntity(_prototypeManager.Index(HumanoidCharacterProfile.DefaultSpecies).DollPrototype, MapCoordinates.Nullspace);
}
if (humanoid != null && jobClothes)
{
DebugTools.Assert(job != null);
GiveDummyJobClothes(humanoid, job);
if (_prototypeManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(job.ID)))
{
var loadout = humanoid.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), _playerManager.LocalSession, humanoid.Species, EntMan, _prototypeManager);
GiveDummyLoadout(loadout);
}
}
}
/// <summary>
/// Gets the highest priority job for the profile.
/// </summary>
private JobPrototype GetPreferredJob(HumanoidCharacterProfile profile)
{
var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key;
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract (what is resharper smoking?)
return _prototypeManager.Index<JobPrototype>(highPriorityJob.Id ?? SharedGameTicker.FallbackOverflowJob);
}
private void GiveDummyLoadout(RoleLoadout? roleLoadout)
{
if (roleLoadout == null)
return;
var spawnSys = EntMan.System<StationSpawningSystem>();
foreach (var group in roleLoadout.SelectedLoadouts.Values)
{
foreach (var loadout in group)
{
if (!_prototypeManager.Resolve(loadout.Prototype, out var loadoutProto))
continue;
spawnSys.EquipStartingGear(PreviewDummy, loadoutProto);
}
}
}
/// <summary>
/// Applies the specified job's clothes to the dummy.
/// </summary>
private void GiveDummyJobClothes(HumanoidCharacterProfile profile, JobPrototype job)
{
var inventorySys = EntMan.System<InventorySystem>();
if (!inventorySys.TryGetSlots(PreviewDummy, out var slots))
return;
// Apply loadout
if (profile.Loadouts.TryGetValue(job.ID, out var jobLoadout))
{
foreach (var loadouts in jobLoadout.SelectedLoadouts.Values)
{
foreach (var loadout in loadouts)
{
if (!_prototypeManager.Resolve(loadout.Prototype, out var loadoutProto))
continue;
// TODO: Need some way to apply starting gear to an entity and replace existing stuff coz holy fucking shit dude.
foreach (var slot in slots)
{
// Try startinggear first
if (_prototypeManager.Resolve(loadoutProto.StartingGear, out var loadoutGear))
{
var itemType = ((IEquipmentLoadout) loadoutGear).GetGear(slot.Name);
if (inventorySys.TryUnequip(PreviewDummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
{
EntMan.DeleteEntity(unequippedItem.Value);
}
if (itemType != string.Empty)
{
var item = EntMan.SpawnEntity(itemType, MapCoordinates.Nullspace);
inventorySys.TryEquip(PreviewDummy, item, slot.Name, true, true);
}
}
else
{
var itemType = ((IEquipmentLoadout) loadoutProto).GetGear(slot.Name);
if (inventorySys.TryUnequip(PreviewDummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
{
EntMan.DeleteEntity(unequippedItem.Value);
}
if (itemType != string.Empty)
{
var item = EntMan.SpawnEntity(itemType, MapCoordinates.Nullspace);
inventorySys.TryEquip(PreviewDummy, item, slot.Name, true, true);
}
}
}
}
}
}
if (!_prototypeManager.Resolve(job.StartingGear, out var gear))
return;
foreach (var slot in slots)
{
var itemType = ((IEquipmentLoadout) gear).GetGear(slot.Name);
if (inventorySys.TryUnequip(PreviewDummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
{
EntMan.DeleteEntity(unequippedItem.Value);
}
if (itemType != string.Empty)
{
var item = EntMan.SpawnEntity(itemType, MapCoordinates.Nullspace);
inventorySys.TryEquip(PreviewDummy, item, slot.Name, true, true);
}
}
}
}

View File

@ -0,0 +1,82 @@
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Client.Lobby.UI.ProfileEditorControls;
public sealed partial class ProfilePreviewSpriteView : SpriteView
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
/// <summary>
/// Entity used for the profile editor preview
/// </summary>
public EntityUid PreviewDummy;
public ProfilePreviewSpriteView()
{
IoCManager.InjectDependencies(this);
}
/// <summary>
/// Reloads the entire dummy entity for preview.
/// </summary>
/// <remarks>
/// This is expensive so not recommended to run if you have a slider.
/// </remarks>
public void LoadPreview(ICharacterProfile profile, JobPrototype? jobOverride = null, bool showClothes = true)
{
EntMan.DeleteEntity(PreviewDummy);
PreviewDummy = EntityUid.Invalid;
switch (profile)
{
case HumanoidCharacterProfile humanoid:
LoadHumanoidEntity(humanoid, jobOverride, showClothes);
break;
default:
throw new ArgumentException("Only humanoid profiles are implemented in ProfilePreviewSpriteView");
}
SetEntity(PreviewDummy);
SetName(profile.Name);
}
/// <summary>
/// Sets the preview entity's name without reloading anything else.
/// </summary>
public void SetName(string newName)
{
EntMan.System<MetaDataSystem>().SetEntityName(PreviewDummy, newName);
}
/// <summary>
/// A slim reload that only updates the entity itself and not any of the job entities, etc.
/// </summary>
public void ReloadProfilePreview(ICharacterProfile profile)
{
switch (profile)
{
case HumanoidCharacterProfile humanoid:
ReloadHumanoidEntity(humanoid);
break;
default:
throw new ArgumentException("Only humanoid profiles are implemented in ProfilePreviewSpriteView");
}
}
public void ClearPreview()
{
EntMan.DeleteEntity(PreviewDummy);
PreviewDummy = EntityUid.Invalid;
}
protected override void ExitedTree()
{
base.ExitedTree();
ClearPreview();
}
}