diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs
index 25490874e9..b28c6a11fb 100644
--- a/Content.Client/Entry/EntryPoint.cs
+++ b/Content.Client/Entry/EntryPoint.cs
@@ -10,10 +10,10 @@ using Content.Client.Info;
using Content.Client.Input;
using Content.Client.IoC;
using Content.Client.Launcher;
+using Content.Client.Lobby;
using Content.Client.MainMenu;
using Content.Client.Parallax.Managers;
using Content.Client.Players.PlayTimeTracking;
-using Content.Client.Preferences;
using Content.Client.Radiation.Overlays;
using Content.Client.Replay;
using Content.Client.Screenshot;
diff --git a/Content.Client/IoC/ClientContentIoC.cs b/Content.Client/IoC/ClientContentIoC.cs
index 65e95b76f0..4703915ae7 100644
--- a/Content.Client/IoC/ClientContentIoC.cs
+++ b/Content.Client/IoC/ClientContentIoC.cs
@@ -2,23 +2,20 @@ using Content.Client.Administration.Managers;
using Content.Client.Changelog;
using Content.Client.Chat.Managers;
using Content.Client.Clickable;
-using Content.Client.Options;
using Content.Client.Eui;
using Content.Client.GhostKick;
using Content.Client.Info;
using Content.Client.Launcher;
using Content.Client.Parallax.Managers;
using Content.Client.Players.PlayTimeTracking;
-using Content.Client.Preferences;
using Content.Client.Screenshot;
using Content.Client.Fullscreen;
using Content.Client.Stylesheets;
using Content.Client.Viewport;
using Content.Client.Voting;
-using Content.Shared.Administration;
using Content.Shared.Administration.Logs;
-using Content.Shared.Module;
using Content.Client.Guidebook;
+using Content.Client.Lobby;
using Content.Client.Replay;
using Content.Shared.Administration.Managers;
using Content.Shared.Players.PlayTimeTracking;
diff --git a/Content.Client/Preferences/ClientPreferencesManager.cs b/Content.Client/Lobby/ClientPreferencesManager.cs
similarity index 97%
rename from Content.Client/Preferences/ClientPreferencesManager.cs
rename to Content.Client/Lobby/ClientPreferencesManager.cs
index 89cee7bf79..3f01e1a8f6 100644
--- a/Content.Client/Preferences/ClientPreferencesManager.cs
+++ b/Content.Client/Lobby/ClientPreferencesManager.cs
@@ -2,12 +2,10 @@ using System.Linq;
using Content.Shared.Preferences;
using Robust.Client;
using Robust.Client.Player;
-using Robust.Shared.Configuration;
using Robust.Shared.Network;
-using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
-namespace Content.Client.Preferences
+namespace Content.Client.Lobby
{
///
/// Receives and from the server during the initial
diff --git a/Content.Client/Preferences/IClientPreferencesManager.cs b/Content.Client/Lobby/IClientPreferencesManager.cs
similarity index 92%
rename from Content.Client/Preferences/IClientPreferencesManager.cs
rename to Content.Client/Lobby/IClientPreferencesManager.cs
index e55d6b600c..45a770b162 100644
--- a/Content.Client/Preferences/IClientPreferencesManager.cs
+++ b/Content.Client/Lobby/IClientPreferencesManager.cs
@@ -1,7 +1,6 @@
-using System;
using Content.Shared.Preferences;
-namespace Content.Client.Preferences
+namespace Content.Client.Lobby
{
public interface IClientPreferencesManager
{
diff --git a/Content.Client/Lobby/LobbyState.cs b/Content.Client/Lobby/LobbyState.cs
index 91730020a4..1aabc4ff38 100644
--- a/Content.Client/Lobby/LobbyState.cs
+++ b/Content.Client/Lobby/LobbyState.cs
@@ -3,8 +3,6 @@ using Content.Client.GameTicking.Managers;
using Content.Client.LateJoin;
using Content.Client.Lobby.UI;
using Content.Client.Message;
-using Content.Client.Preferences;
-using Content.Client.Preferences.UI;
using Content.Client.UserInterface.Systems.Chat;
using Content.Client.Voting;
using Robust.Client;
@@ -12,8 +10,6 @@ using Robust.Client.Console;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
-using Robust.Shared.Configuration;
-using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
@@ -25,20 +21,15 @@ namespace Content.Client.Lobby
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
- [Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IVoteManager _voteManager = default!;
- [Dependency] private readonly IConfigurationManager _configurationManager = default!;
-
- [ViewVariables] private CharacterSetupGui? _characterSetup;
private ClientGameTicker _gameTicker = default!;
private ContentAudioSystem _contentAudioSystem = default!;
protected override Type? LinkedScreenType { get; } = typeof(LobbyGui);
- private LobbyGui? _lobby;
+ public LobbyGui? Lobby;
protected override void Startup()
{
@@ -47,45 +38,23 @@ namespace Content.Client.Lobby
return;
}
- _lobby = (LobbyGui) _userInterfaceManager.ActiveScreen;
+ Lobby = (LobbyGui) _userInterfaceManager.ActiveScreen;
var chatController = _userInterfaceManager.GetUIController();
_gameTicker = _entityManager.System();
_contentAudioSystem = _entityManager.System();
_contentAudioSystem.LobbySoundtrackChanged += UpdateLobbySoundtrackInfo;
- _characterSetup = new CharacterSetupGui(_entityManager, _resourceCache, _preferencesManager,
- _prototypeManager, _configurationManager);
- LayoutContainer.SetAnchorPreset(_characterSetup, LayoutContainer.LayoutPreset.Wide);
- _lobby.CharacterSetupState.AddChild(_characterSetup);
chatController.SetMainChat(true);
- _voteManager.SetPopupContainer(_lobby.VoteContainer);
-
- _characterSetup.CloseButton.OnPressed += _ =>
- {
- // Reset sliders etc.
- _characterSetup?.UpdateControls();
-
- var controller = _userInterfaceManager.GetUIController();
- controller.SetClothes(true);
- controller.UpdateProfile();
- _lobby.SwitchState(LobbyGui.LobbyGuiState.Default);
- };
-
- _characterSetup.SaveButton.OnPressed += _ =>
- {
- _characterSetup.Save();
- _userInterfaceManager.GetUIController().ReloadProfile();
- };
-
- LayoutContainer.SetAnchorPreset(_lobby, LayoutContainer.LayoutPreset.Wide);
- _lobby.ServerName.Text = _baseClient.GameInfo?.ServerName; //The eye of refactor gazes upon you...
+ _voteManager.SetPopupContainer(Lobby.VoteContainer);
+ LayoutContainer.SetAnchorPreset(Lobby, LayoutContainer.LayoutPreset.Wide);
+ Lobby.ServerName.Text = _baseClient.GameInfo?.ServerName; //The eye of refactor gazes upon you...
UpdateLobbyUi();
- _lobby.CharacterPreview.CharacterSetupButton.OnPressed += OnSetupPressed;
- _lobby.ReadyButton.OnPressed += OnReadyPressed;
- _lobby.ReadyButton.OnToggled += OnReadyToggled;
+ Lobby.CharacterPreview.CharacterSetupButton.OnPressed += OnSetupPressed;
+ Lobby.ReadyButton.OnPressed += OnReadyPressed;
+ Lobby.ReadyButton.OnToggled += OnReadyToggled;
_gameTicker.InfoBlobUpdated += UpdateLobbyUi;
_gameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
@@ -103,20 +72,23 @@ namespace Content.Client.Lobby
_voteManager.ClearPopupContainer();
- _lobby!.CharacterPreview.CharacterSetupButton.OnPressed -= OnSetupPressed;
- _lobby!.ReadyButton.OnPressed -= OnReadyPressed;
- _lobby!.ReadyButton.OnToggled -= OnReadyToggled;
+ Lobby!.CharacterPreview.CharacterSetupButton.OnPressed -= OnSetupPressed;
+ Lobby!.ReadyButton.OnPressed -= OnReadyPressed;
+ Lobby!.ReadyButton.OnToggled -= OnReadyToggled;
- _lobby = null;
+ Lobby = null;
+ }
- _characterSetup?.Dispose();
- _characterSetup = null;
+ public void SwitchState(LobbyGui.LobbyGuiState state)
+ {
+ // Yeah I hate this but LobbyState contains all the badness for now.
+ Lobby?.SwitchState(state);
}
private void OnSetupPressed(BaseButton.ButtonEventArgs args)
{
SetReady(false);
- _lobby!.SwitchState(LobbyGui.LobbyGuiState.CharacterSetup);
+ Lobby?.SwitchState(LobbyGui.LobbyGuiState.CharacterSetup);
}
private void OnReadyPressed(BaseButton.ButtonEventArgs args)
@@ -138,13 +110,13 @@ namespace Content.Client.Lobby
{
if (_gameTicker.IsGameStarted)
{
- _lobby!.StartTime.Text = string.Empty;
+ Lobby!.StartTime.Text = string.Empty;
var roundTime = _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan);
- _lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-time", ("hours", roundTime.Hours), ("minutes", roundTime.Minutes));
+ Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-time", ("hours", roundTime.Hours), ("minutes", roundTime.Minutes));
return;
}
- _lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
+ Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
string text;
if (_gameTicker.Paused)
@@ -153,7 +125,7 @@ namespace Content.Client.Lobby
}
else if (_gameTicker.StartTime < _gameTiming.CurTime)
{
- _lobby!.StartTime.Text = Loc.GetString("lobby-state-soon");
+ Lobby!.StartTime.Text = Loc.GetString("lobby-state-soon");
return;
}
else
@@ -170,7 +142,7 @@ namespace Content.Client.Lobby
}
}
- _lobby!.StartTime.Text = Loc.GetString("lobby-state-round-start-countdown-text", ("timeLeft", text));
+ Lobby!.StartTime.Text = Loc.GetString("lobby-state-round-start-countdown-text", ("timeLeft", text));
}
private void LobbyStatusUpdated()
@@ -181,31 +153,31 @@ namespace Content.Client.Lobby
private void LobbyLateJoinStatusUpdated()
{
- _lobby!.ReadyButton.Disabled = _gameTicker.DisallowedLateJoin;
+ Lobby!.ReadyButton.Disabled = _gameTicker.DisallowedLateJoin;
}
private void UpdateLobbyUi()
{
if (_gameTicker.IsGameStarted)
{
- _lobby!.ReadyButton.Text = Loc.GetString("lobby-state-ready-button-join-state");
- _lobby!.ReadyButton.ToggleMode = false;
- _lobby!.ReadyButton.Pressed = false;
- _lobby!.ObserveButton.Disabled = false;
+ Lobby!.ReadyButton.Text = Loc.GetString("lobby-state-ready-button-join-state");
+ Lobby!.ReadyButton.ToggleMode = false;
+ Lobby!.ReadyButton.Pressed = false;
+ Lobby!.ObserveButton.Disabled = false;
}
else
{
- _lobby!.StartTime.Text = string.Empty;
- _lobby!.ReadyButton.Text = Loc.GetString(_lobby!.ReadyButton.Pressed ? "lobby-state-player-status-ready": "lobby-state-player-status-not-ready");
- _lobby!.ReadyButton.ToggleMode = true;
- _lobby!.ReadyButton.Disabled = false;
- _lobby!.ReadyButton.Pressed = _gameTicker.AreWeReady;
- _lobby!.ObserveButton.Disabled = true;
+ Lobby!.StartTime.Text = string.Empty;
+ Lobby!.ReadyButton.Text = Loc.GetString(Lobby!.ReadyButton.Pressed ? "lobby-state-player-status-ready": "lobby-state-player-status-not-ready");
+ Lobby!.ReadyButton.ToggleMode = true;
+ Lobby!.ReadyButton.Disabled = false;
+ Lobby!.ReadyButton.Pressed = _gameTicker.AreWeReady;
+ Lobby!.ObserveButton.Disabled = true;
}
if (_gameTicker.ServerInfoBlob != null)
{
- _lobby!.ServerInfo.SetInfoBlob(_gameTicker.ServerInfoBlob);
+ Lobby!.ServerInfo.SetInfoBlob(_gameTicker.ServerInfoBlob);
}
}
@@ -213,7 +185,7 @@ namespace Content.Client.Lobby
{
if (ev.SoundtrackFilename == null)
{
- _lobby!.LobbySong.SetMarkup(Loc.GetString("lobby-state-song-no-song-text"));
+ Lobby!.LobbySong.SetMarkup(Loc.GetString("lobby-state-song-no-song-text"));
}
else if (
ev.SoundtrackFilename != null
@@ -234,7 +206,7 @@ namespace Content.Client.Lobby
("songTitle", title),
("songArtist", artist));
- _lobby!.LobbySong.SetMarkup(markup);
+ Lobby!.LobbySong.SetMarkup(markup);
}
}
@@ -242,11 +214,11 @@ namespace Content.Client.Lobby
{
if (_gameTicker.LobbyBackground != null)
{
- _lobby!.Background.Texture = _resourceCache.GetResource(_gameTicker.LobbyBackground );
+ Lobby!.Background.Texture = _resourceCache.GetResource(_gameTicker.LobbyBackground );
}
else
{
- _lobby!.Background.Texture = null;
+ Lobby!.Background.Texture = null;
}
}
diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs
index 9eb259657d..ae9196c110 100644
--- a/Content.Client/Lobby/LobbyUIController.cs
+++ b/Content.Client/Lobby/LobbyUIController.cs
@@ -2,190 +2,292 @@ using System.Linq;
using Content.Client.Humanoid;
using Content.Client.Inventory;
using Content.Client.Lobby.UI;
-using Content.Client.Preferences;
-using Content.Client.Preferences.UI;
+using Content.Client.Players.PlayTimeTracking;
using Content.Client.Station;
+using Content.Shared.CCVar;
using Content.Shared.Clothing;
using Content.Shared.GameTicking;
+using Content.Shared.Humanoid;
+using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
-using Content.Shared.Preferences.Loadouts.Effects;
using Content.Shared.Roles;
+using Content.Shared.Traits;
+using Robust.Client.Player;
+using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
+using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.Manager;
+using Robust.Shared.Utility;
namespace Content.Client.Lobby;
public sealed class LobbyUIController : UIController, IOnStateEntered, IOnStateExited
{
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
- [Dependency] private readonly IStateManager _stateManager = default!;
+ [Dependency] private readonly IConfigurationManager _configurationManager = default!;
+ [Dependency] private readonly IFileDialogManager _dialogManager = default!;
+ [Dependency] private readonly ILogManager _logManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IResourceCache _resourceCache = default!;
+ [Dependency] private readonly IStateManager _stateManager = default!;
+ [Dependency] private readonly JobRequirementsManager _requirements = default!;
+ [Dependency] private readonly MarkingManager _markings = default!;
[UISystemDependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
[UISystemDependency] private readonly ClientInventorySystem _inventory = default!;
[UISystemDependency] private readonly StationSpawningSystem _spawn = default!;
- private LobbyCharacterPreviewPanel? _previewPanel;
-
- private bool _showClothes = true;
-
- /*
- * Each character profile has its own dummy. There is also a dummy for the lobby screen + character editor
- * that is shared too.
- */
+ private CharacterSetupGui? _characterSetup;
+ private HumanoidProfileEditor? _profileEditor;
///
- /// Preview dummy for role gear.
+ /// This is the characher preview panel in the chat. This should only update if their character updates.
///
- private EntityUid? _previewDummy;
+ private LobbyCharacterPreviewPanel? PreviewPanel => GetLobbyPreview();
///
- /// If we currently have a job prototype selected.
+ /// This is the modified profile currently being edited.
///
- private JobPrototype? _dummyJob;
+ private HumanoidCharacterProfile? EditedProfile => _profileEditor?.Profile;
- // TODO: Load the species directly and don't update entity ever.
- public event Action? PreviewDummyUpdated;
-
- private HumanoidCharacterProfile? _profile;
+ private int? EditedSlot => _profileEditor?.CharacterSlot;
public override void Initialize()
{
base.Initialize();
+ _prototypeManager.PrototypesReloaded += OnProtoReload;
_preferencesManager.OnServerDataLoaded += PreferencesDataLoaded;
+ _requirements.Updated += OnRequirementsUpdated;
+
+ _configurationManager.OnValueChanged(CCVars.FlavorText, args =>
+ {
+ _profileEditor?.RefreshFlavorText();
+ });
+
+ _configurationManager.OnValueChanged(CCVars.GameRoleTimers, args =>
+ {
+ _profileEditor?.RefreshAntags();
+ _profileEditor?.RefreshJobs();
+ _profileEditor?.RefreshLoadouts();
+ });
+ }
+
+ private LobbyCharacterPreviewPanel? GetLobbyPreview()
+ {
+ if (_stateManager.CurrentState is LobbyState lobby)
+ {
+ return lobby.Lobby?.CharacterPreview;
+ }
+
+ return null;
+ }
+
+ private void OnRequirementsUpdated()
+ {
+ if (_profileEditor != null)
+ {
+ _profileEditor.RefreshAntags();
+ _profileEditor.RefreshJobs();
+ }
+ }
+
+ private void OnProtoReload(PrototypesReloadedEventArgs obj)
+ {
+ if (_profileEditor != null)
+ {
+ if (obj.WasModified())
+ {
+ _profileEditor.RefreshAntags();
+ }
+
+ if (obj.WasModified() ||
+ obj.WasModified())
+ {
+ _profileEditor.RefreshJobs();
+ }
+
+ if (obj.WasModified() ||
+ obj.WasModified() ||
+ obj.WasModified())
+ {
+ _profileEditor.RefreshLoadouts();
+ }
+
+ if (obj.WasModified())
+ {
+ _profileEditor.RefreshSpecies();
+ }
+
+ if (obj.WasModified())
+ {
+ _profileEditor.RefreshTraits();
+ }
+ }
}
private void PreferencesDataLoaded()
{
- UpdateProfile();
- }
-
- public void OnStateEntered(LobbyState state)
- {
- }
-
- public void OnStateExited(LobbyState state)
- {
- EntityManager.DeleteEntity(_previewDummy);
- _previewDummy = null;
- }
-
- public void SetPreviewPanel(LobbyCharacterPreviewPanel? panel)
- {
- _previewPanel = panel;
- ReloadProfile();
- }
-
- public void SetClothes(bool value)
- {
- if (_showClothes == value)
- return;
-
- _showClothes = value;
- ReloadCharacterUI();
- }
-
- public void SetDummyJob(JobPrototype? job)
- {
- _dummyJob = job;
- ReloadCharacterUI();
- }
-
- ///
- /// Updates the character only with the specified profile change.
- ///
- public void ReloadProfile()
- {
- // Test moment
- if (_profile == null || _stateManager.CurrentState is not LobbyState)
- return;
-
- // Ignore job clothes and the likes so we don't spam entities out every frame of color changes.
- var previewDummy = EnsurePreviewDummy(_profile);
- _humanoid.LoadProfile(previewDummy, _profile);
- }
-
- ///
- /// Updates the currently selected character's preview.
- ///
- public void ReloadCharacterUI()
- {
- // Test moment
- if (_profile == null || _stateManager.CurrentState is not LobbyState)
- return;
-
- EntityManager.DeleteEntity(_previewDummy);
- _previewDummy = null;
- _previewDummy = EnsurePreviewDummy(_profile);
- _previewPanel?.SetSprite(_previewDummy.Value);
- _previewPanel?.SetSummaryText(_profile.Summary);
- _humanoid.LoadProfile(_previewDummy.Value, _profile);
-
- if (_showClothes)
- GiveDummyJobClothesLoadout(_previewDummy.Value, _profile);
- }
-
- ///
- /// Updates character profile to the default.
- ///
- public void UpdateProfile()
- {
- if (!_preferencesManager.ServerDataLoaded)
- {
- _profile = null;
- return;
- }
-
- if (_preferencesManager.Preferences?.SelectedCharacter is HumanoidCharacterProfile selectedCharacter)
- {
- _profile = selectedCharacter;
- _previewPanel?.SetLoaded(true);
- }
- else
- {
- _previewPanel?.SetSummaryText(string.Empty);
- _previewPanel?.SetLoaded(false);
- }
-
- ReloadCharacterUI();
- }
-
- public void UpdateProfile(HumanoidCharacterProfile? profile)
- {
- if (_profile?.Equals(profile) == true)
- return;
+ PreviewPanel?.SetLoaded(true);
if (_stateManager.CurrentState is not LobbyState)
return;
- _profile = profile;
+ ReloadCharacterSetup();
}
- private EntityUid EnsurePreviewDummy(HumanoidCharacterProfile profile)
+ public void OnStateEntered(LobbyState state)
{
- if (_previewDummy != null)
- return _previewDummy.Value;
-
- _previewDummy = EntityManager.SpawnEntity(_prototypeManager.Index(profile.Species).DollPrototype, MapCoordinates.Nullspace);
- PreviewDummyUpdated?.Invoke(_previewDummy.Value);
- return _previewDummy.Value;
+ PreviewPanel?.SetLoaded(_preferencesManager.ServerDataLoaded);
+ ReloadCharacterSetup();
}
+ public void OnStateExited(LobbyState state)
+ {
+ PreviewPanel?.SetLoaded(false);
+ _profileEditor?.Dispose();
+ _characterSetup?.Dispose();
+
+ _characterSetup = null;
+ _profileEditor = null;
+ }
+
+ ///
+ /// Reloads every single character setup control.
+ ///
+ public void ReloadCharacterSetup()
+ {
+ RefreshLobbyPreview();
+ var (characterGui, profileEditor) = EnsureGui();
+ characterGui.ReloadCharacterPickers();
+ profileEditor.SetProfile(
+ (HumanoidCharacterProfile?) _preferencesManager.Preferences?.SelectedCharacter,
+ _preferencesManager.Preferences?.SelectedCharacterIndex);
+ }
+
+ ///
+ /// Refreshes the character preview in the lobby chat.
+ ///
+ private void RefreshLobbyPreview()
+ {
+ if (PreviewPanel == null)
+ return;
+
+ // Get selected character, load it, then set it
+ var character = _preferencesManager.Preferences?.SelectedCharacter;
+
+ if (character is not HumanoidCharacterProfile humanoid)
+ {
+ PreviewPanel.SetSprite(EntityUid.Invalid);
+ PreviewPanel.SetSummaryText(string.Empty);
+ return;
+ }
+
+ var dummy = LoadProfileEntity(humanoid, null, true);
+ PreviewPanel.SetSprite(dummy);
+ PreviewPanel.SetSummaryText(humanoid.Summary);
+ }
+
+ private void SaveProfile()
+ {
+ DebugTools.Assert(EditedProfile != null);
+
+ if (EditedProfile == null || EditedSlot == null)
+ return;
+
+ var selected = _preferencesManager.Preferences?.SelectedCharacterIndex;
+
+ if (selected == null)
+ return;
+
+ _preferencesManager.UpdateCharacter(EditedProfile, EditedSlot.Value);
+ ReloadCharacterSetup();
+ }
+
+ private (CharacterSetupGui, HumanoidProfileEditor) EnsureGui()
+ {
+ if (_characterSetup != null && _profileEditor != null)
+ {
+ _characterSetup.Visible = true;
+ _profileEditor.Visible = true;
+ return (_characterSetup, _profileEditor);
+ }
+
+ _profileEditor = new HumanoidProfileEditor(
+ _preferencesManager,
+ _configurationManager,
+ EntityManager,
+ _dialogManager,
+ _logManager,
+ _playerManager,
+ _prototypeManager,
+ _requirements,
+ _markings);
+
+ _characterSetup = new CharacterSetupGui(EntityManager, _prototypeManager, _resourceCache, _preferencesManager, _profileEditor);
+
+ _characterSetup.CloseButton.OnPressed += _ =>
+ {
+ // Reset sliders etc.
+ _profileEditor.SetProfile(null, null);
+ _profileEditor.Visible = false;
+
+ if (_stateManager.CurrentState is LobbyState lobbyGui)
+ {
+ lobbyGui.SwitchState(LobbyGui.LobbyGuiState.Default);
+ }
+ };
+
+ _profileEditor.Save += SaveProfile;
+
+ _characterSetup.SelectCharacter += args =>
+ {
+ _preferencesManager.SelectCharacter(args);
+ ReloadCharacterSetup();
+ };
+
+ _characterSetup.DeleteCharacter += args =>
+ {
+ _preferencesManager.DeleteCharacter(args);
+
+ // Reload everything
+ if (EditedSlot == args)
+ {
+ ReloadCharacterSetup();
+ }
+ else
+ {
+ // Only need to reload character pickers
+ _characterSetup?.ReloadCharacterPickers();
+ }
+ };
+
+ if (_stateManager.CurrentState is LobbyState lobby)
+ {
+ lobby.Lobby?.CharacterSetupState.AddChild(_characterSetup);
+ }
+
+ return (_characterSetup, _profileEditor);
+ }
+
+ #region Helpers
+
///
/// Applies the highest priority job's clothes to the dummy.
///
- public void GiveDummyJobClothesLoadout(EntityUid dummy, HumanoidCharacterProfile profile)
+ public void GiveDummyJobClothesLoadout(EntityUid dummy, JobPrototype? jobProto, HumanoidCharacterProfile profile)
{
- var job = _dummyJob ?? GetPreferredJob(profile);
+ var job = jobProto ?? GetPreferredJob(profile);
GiveDummyJobClothes(dummy, profile, job);
if (_prototypeManager.HasIndex(LoadoutSystem.GetJobPrototype(job.ID)))
{
- var loadout = profile.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), EntityManager, _prototypeManager);
+ var loadout = profile.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), profile.Species, EntityManager, _prototypeManager);
GiveDummyLoadout(dummy, loadout);
}
}
@@ -279,8 +381,39 @@ public sealed class LobbyUIController : UIController, IOnStateEntered
+ /// Loads the profile onto a dummy entity.
+ ///
+ public EntityUid LoadProfileEntity(HumanoidCharacterProfile? humanoid, JobPrototype? job, bool jobClothes)
{
- return _previewDummy;
+ EntityUid dummyEnt;
+
+ if (humanoid is not null)
+ {
+ var dummy = _prototypeManager.Index(humanoid.Species).DollPrototype;
+ dummyEnt = EntityManager.SpawnEntity(dummy, MapCoordinates.Nullspace);
+ }
+ else
+ {
+ dummyEnt = EntityManager.SpawnEntity(_prototypeManager.Index(SharedHumanoidAppearanceSystem.DefaultSpecies).DollPrototype, MapCoordinates.Nullspace);
+ }
+
+ _humanoid.LoadProfile(dummyEnt, humanoid);
+
+ if (humanoid != null && jobClothes)
+ {
+ job ??= GetPreferredJob(humanoid);
+ GiveDummyJobClothes(dummyEnt, humanoid, job);
+
+ if (_prototypeManager.HasIndex(LoadoutSystem.GetJobPrototype(job.ID)))
+ {
+ var loadout = humanoid.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), humanoid.Species, EntityManager, _prototypeManager);
+ GiveDummyLoadout(dummyEnt, loadout);
+ }
+ }
+
+ return dummyEnt;
}
+
+ #endregion
}
diff --git a/Content.Client/Lobby/UI/CharacterPickerButton.xaml b/Content.Client/Lobby/UI/CharacterPickerButton.xaml
new file mode 100644
index 0000000000..af1e640aad
--- /dev/null
+++ b/Content.Client/Lobby/UI/CharacterPickerButton.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Lobby/UI/CharacterPickerButton.xaml.cs b/Content.Client/Lobby/UI/CharacterPickerButton.xaml.cs
new file mode 100644
index 0000000000..2ad8de7445
--- /dev/null
+++ b/Content.Client/Lobby/UI/CharacterPickerButton.xaml.cs
@@ -0,0 +1,92 @@
+using System.Linq;
+using Content.Client.Humanoid;
+using Content.Shared.Clothing;
+using Content.Shared.Humanoid;
+using Content.Shared.Humanoid.Prototypes;
+using Content.Shared.Preferences;
+using Content.Shared.Preferences.Loadouts;
+using Content.Shared.Roles;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Lobby.UI;
+
+///
+/// Holds character data on the side of the setup GUI.
+///
+[GenerateTypedNameReferences]
+public sealed partial class CharacterPickerButton : ContainerButton
+{
+ private IEntityManager _entManager;
+
+ private EntityUid _previewDummy;
+
+ ///
+ /// Invoked if we should delete the attached character
+ ///
+ public event Action? OnDeletePressed;
+
+ public CharacterPickerButton(
+ IEntityManager entityManager,
+ IPrototypeManager prototypeManager,
+ 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)
+ {
+ _previewDummy = entityManager.SpawnEntity(prototypeManager.Index(SharedHumanoidAppearanceSystem.DefaultSpecies).DollPrototype, MapCoordinates.Nullspace);
+ }
+ else
+ {
+ _previewDummy = UserInterfaceManager.GetUIController()
+ .LoadProfileEntity(humanoid, null, true);
+
+ var highPriorityJob = humanoid.JobPriorities.SingleOrDefault(p => p.Value == JobPriority.High).Key;
+ if (highPriorityJob != null)
+ {
+ var jobName = prototypeManager.Index(highPriorityJob).LocalizedName;
+ description = $"{description}\n{jobName}";
+ }
+ }
+
+ Pressed = isSelected;
+ DeleteButton.Visible = !isSelected;
+
+ View.SetEntity(_previewDummy);
+ DescriptionLabel.Text = description;
+
+ ConfirmDeleteButton.OnPressed += _ =>
+ {
+ Parent?.RemoveChild(this);
+ Parent?.RemoveChild(ConfirmDeleteButton);
+ OnDeletePressed?.Invoke();
+ };
+
+ DeleteButton.OnPressed += _ =>
+ {
+ DeleteButton.Visible = false;
+ ConfirmDeleteButton.Visible = true;
+ };
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing)
+ return;
+
+ _entManager.DeleteEntity(_previewDummy);
+ _previewDummy = default;
+ }
+}
diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml b/Content.Client/Lobby/UI/CharacterSetupGui.xaml
similarity index 91%
rename from Content.Client/Preferences/UI/CharacterSetupGui.xaml
rename to Content.Client/Lobby/UI/CharacterSetupGui.xaml
index 35067eebfd..f83be26588 100644
--- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml
+++ b/Content.Client/Lobby/UI/CharacterSetupGui.xaml
@@ -17,10 +17,6 @@
-