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:
parent
e3eb8083e8
commit
abb13de3dd
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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'}"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue