From fcd6c25242c195266c3b4c4aa2ed78922683567c Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:54:54 +1000 Subject: [PATCH] LobbyUI fixes (#27033) * LobbyUI fixes I have no idea which were bugs prior but anyway fix stuff. * More fixes * Test moment --- Content.Client/Lobby/LobbyState.cs | 8 +- Content.Client/Lobby/LobbyUIController.cs | 101 ++++++++++++++---- .../Preferences/UI/CharacterSetupGui.xaml.cs | 7 +- .../UI/HumanoidProfileEditor.xaml.cs | 81 +++++++++----- .../Preferences/UI/RequirementsSelector.cs | 4 +- .../Preferences/HumanoidCharacterProfile.cs | 18 ++++ .../Preferences/Loadouts/RoleLoadout.cs | 12 +++ 7 files changed, 181 insertions(+), 50 deletions(-) diff --git a/Content.Client/Lobby/LobbyState.cs b/Content.Client/Lobby/LobbyState.cs index 98c109afde..91730020a4 100644 --- a/Content.Client/Lobby/LobbyState.cs +++ b/Content.Client/Lobby/LobbyState.cs @@ -64,13 +64,19 @@ namespace Content.Client.Lobby _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().UpdateCharacterUI(); + _userInterfaceManager.GetUIController().ReloadProfile(); }; LayoutContainer.SetAnchorPreset(_lobby, LayoutContainer.LayoutPreset.Wide); diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs index 19f43e0575..9eb259657d 100644 --- a/Content.Client/Lobby/LobbyUIController.cs +++ b/Content.Client/Lobby/LobbyUIController.cs @@ -3,6 +3,7 @@ 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.Station; using Content.Shared.Clothing; using Content.Shared.GameTicking; @@ -30,6 +31,8 @@ public sealed class LobbyUIController : UIController, IOnStateEntered - /// If we currently have a loadout selected. + /// If we currently have a job prototype selected. /// private JobPrototype? _dummyJob; // TODO: Load the species directly and don't update entity ever. public event Action? PreviewDummyUpdated; + private HumanoidCharacterProfile? _profile; + public override void Initialize() { base.Initialize(); @@ -56,7 +61,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered + /// Updates the character only with the specified profile change. + /// + public void ReloadProfile() { // Test moment - if (_stateManager.CurrentState is not LobbyState) + 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) { - _previewPanel?.SetLoaded(false); + _profile = null; return; } - _previewPanel?.SetLoaded(true); - - if (_preferencesManager.Preferences?.SelectedCharacter is not HumanoidCharacterProfile selectedCharacter) + if (_preferencesManager.Preferences?.SelectedCharacter is HumanoidCharacterProfile selectedCharacter) { - _previewPanel?.SetSummaryText(string.Empty); + _profile = selectedCharacter; + _previewPanel?.SetLoaded(true); } else { - EntityManager.DeleteEntity(_previewDummy); - _previewDummy = EntityManager.SpawnEntity(_prototypeManager.Index(selectedCharacter.Species).DollPrototype, MapCoordinates.Nullspace); - _previewPanel?.SetSprite(_previewDummy.Value); - _previewPanel?.SetSummaryText(selectedCharacter.Summary); - _humanoid.LoadProfile(_previewDummy.Value, selectedCharacter); - - GiveDummyJobClothesLoadout(_previewDummy.Value, selectedCharacter); - PreviewDummyUpdated?.Invoke(_previewDummy.Value); + _previewPanel?.SetSummaryText(string.Empty); + _previewPanel?.SetLoaded(false); } + + ReloadCharacterUI(); + } + + public void UpdateProfile(HumanoidCharacterProfile? profile) + { + if (_profile?.Equals(profile) == true) + return; + + if (_stateManager.CurrentState is not LobbyState) + return; + + _profile = profile; + } + + private EntityUid EnsurePreviewDummy(HumanoidCharacterProfile profile) + { + if (_previewDummy != null) + return _previewDummy.Value; + + _previewDummy = EntityManager.SpawnEntity(_prototypeManager.Index(profile.Species).DollPrototype, MapCoordinates.Nullspace); + PreviewDummyUpdated?.Invoke(_previewDummy.Value); + return _previewDummy.Value; } /// diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs index 0dcd5e6ad3..ea8de09ab5 100644 --- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs +++ b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs @@ -97,9 +97,14 @@ namespace Content.Client.Preferences.UI UpdateUI(); } + public void UpdateControls() + { + // Reset sliders etc. upon going going back to GUI. + _humanoidProfileEditor.LoadServerData(); + } + private void UpdateUI() { - UserInterfaceManager.GetUIController().UpdateCharacterUI(); var numberOfFullSlots = 0; var characterButtonsGroup = new ButtonGroup(); Characters.RemoveAllChildren(); diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index e1135523f1..59a44d0e4b 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -190,7 +190,7 @@ namespace Content.Client.Preferences.UI return; Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithHairStyleName(newStyle.id)); - IsDirty = true; + SetDirty(); }; _hairPicker.OnColorChanged += newColor => @@ -200,7 +200,7 @@ namespace Content.Client.Preferences.UI Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithHairColor(newColor.marking.MarkingColors[0])); UpdateCMarkingsHair(); - IsDirty = true; + SetDirty(); }; _facialHairPicker.OnMarkingSelect += newStyle => @@ -209,7 +209,7 @@ namespace Content.Client.Preferences.UI return; Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithFacialHairStyleName(newStyle.id)); - IsDirty = true; + SetDirty(); }; _facialHairPicker.OnColorChanged += newColor => @@ -219,7 +219,7 @@ namespace Content.Client.Preferences.UI Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithFacialHairColor(newColor.marking.MarkingColors[0])); UpdateCMarkingsFacialHair(); - IsDirty = true; + SetDirty(); }; _hairPicker.OnSlotRemove += _ => @@ -231,7 +231,7 @@ namespace Content.Client.Preferences.UI ); UpdateHairPickers(); UpdateCMarkingsHair(); - IsDirty = true; + SetDirty(); }; _facialHairPicker.OnSlotRemove += _ => @@ -243,7 +243,7 @@ namespace Content.Client.Preferences.UI ); UpdateHairPickers(); UpdateCMarkingsFacialHair(); - IsDirty = true; + SetDirty(); }; _hairPicker.OnSlotAdd += delegate() @@ -263,7 +263,7 @@ namespace Content.Client.Preferences.UI UpdateHairPickers(); UpdateCMarkingsHair(); - IsDirty = true; + SetDirty(); }; _facialHairPicker.OnSlotAdd += delegate() @@ -283,7 +283,7 @@ namespace Content.Client.Preferences.UI UpdateHairPickers(); UpdateCMarkingsFacialHair(); - IsDirty = true; + SetDirty(); }; #endregion Hair @@ -312,7 +312,7 @@ namespace Content.Client.Preferences.UI Profile = Profile.WithCharacterAppearance( Profile.Appearance.WithEyeColor(newColor)); CMarkings.CurrentEyeColor = Profile.Appearance.EyeColor; - IsDirty = true; + SetDirty(); }; #endregion Eyes @@ -336,7 +336,7 @@ namespace Content.Client.Preferences.UI _preferenceUnavailableButton.SelectId(args.Id); Profile = Profile?.WithPreferenceUnavailable((PreferenceUnavailableMode) args.Id); - IsDirty = true; + SetDirty(); }; _jobPriorities = new List(); @@ -369,7 +369,7 @@ namespace Content.Client.Preferences.UI selector.PreferenceChanged += preference => { Profile = Profile?.WithTraitPreference(trait.ID, preference); - IsDirty = true; + SetDirty(); }; } } @@ -436,6 +436,13 @@ namespace Content.Client.Preferences.UI LoadServerData(); } + ShowClothes.OnToggled += args => + { + var lobby = UserInterfaceManager.GetUIController(); + lobby.SetClothes(args.Pressed); + SetDirty(); + }; + preferencesManager.OnServerDataLoaded += LoadServerData; SpeciesInfoButton.OnPressed += OnSpeciesInfoButtonPressed; @@ -443,6 +450,15 @@ namespace Content.Client.Preferences.UI UpdateSpeciesGuidebookIcon(); IsDirty = false; + controller.UpdateProfile(); + } + + private void SetDirty() + { + var controller = UserInterfaceManager.GetUIController(); + controller.UpdateProfile(Profile); + controller.ReloadCharacterUI(); + IsDirty = true; } private void OnSpeciesInfoButtonPressed(BaseButton.ButtonEventArgs args) @@ -487,13 +503,13 @@ namespace Content.Client.Preferences.UI if (selector.Disabled) { Profile = Profile?.WithAntagPreference(antag.ID, false); - IsDirty = true; + SetDirty(); } selector.PreferenceChanged += preference => { Profile = Profile?.WithAntagPreference(antag.ID, preference); - IsDirty = true; + SetDirty(); }; } @@ -562,7 +578,10 @@ namespace Content.Client.Preferences.UI foreach (var job in jobs) { RoleLoadout? loadout = null; + + // Clone so we don't modify the underlying loadout. Profile?.Loadouts.TryGetValue(LoadoutSystem.GetJobPrototype(job.ID), out loadout); + loadout = loadout?.Clone(); var selector = new JobPrioritySelector(loadout, job, jobLoadoutGroup, _prototypeManager) { Margin = new Thickness(3f, 3f, 3f, 0f), @@ -578,15 +597,13 @@ namespace Content.Client.Preferences.UI selector.LoadoutUpdated += args => { - Profile?.SetLoadout(args); - UserInterfaceManager.GetUIController().UpdateCharacterUI(); - IsDirty = true; + Profile = Profile?.WithLoadout(args); + SetDirty(); }; selector.PriorityChanged += priority => { Profile = Profile?.WithJobPriority(job.ID, priority); - IsDirty = true; foreach (var jobSelector in _jobPriorities) { @@ -602,6 +619,8 @@ namespace Content.Client.Preferences.UI Profile = Profile?.WithJobPriority(jobSelector.Proto.ID, JobPriority.Medium); } } + + SetDirty(); }; } @@ -619,7 +638,7 @@ namespace Content.Client.Preferences.UI return; Profile = Profile.WithFlavorText(content); - IsDirty = true; + SetDirty(); } private void OnMarkingChange(MarkingSet markings) @@ -628,8 +647,10 @@ namespace Content.Client.Preferences.UI return; Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithMarkings(markings.GetForwardEnumerator().ToList())); - UpdatePreview(); IsDirty = true; + var controller = UserInterfaceManager.GetUIController(); + controller.UpdateProfile(Profile); + controller.ReloadProfile(); } private void OnSkinColorOnValueChanged() @@ -683,6 +704,9 @@ namespace Content.Client.Preferences.UI } IsDirty = true; + var controller = UserInterfaceManager.GetUIController(); + controller.UpdateProfile(Profile); + controller.ReloadProfile(); } protected override void Dispose(bool disposing) @@ -698,7 +722,7 @@ namespace Content.Client.Preferences.UI _preferencesManager.OnServerDataLoaded -= LoadServerData; } - private void LoadServerData() + public void LoadServerData() { Profile = (HumanoidCharacterProfile) _preferencesManager.Preferences!.SelectedCharacter; CharacterSlot = _preferencesManager.Preferences.SelectedCharacterIndex; @@ -706,12 +730,13 @@ namespace Content.Client.Preferences.UI UpdateAntagRequirements(); UpdateRoleRequirements(); UpdateControls(); + ShowClothes.Pressed = true; } private void SetAge(int newAge) { Profile = Profile?.WithAge(newAge); - IsDirty = true; + SetDirty(); } private void SetSex(Sex newSex) @@ -732,13 +757,13 @@ namespace Content.Client.Preferences.UI } UpdateGenderControls(); CMarkings.SetSex(newSex); - IsDirty = true; + SetDirty(); } private void SetGender(Gender newGender) { Profile = Profile?.WithGender(newGender); - IsDirty = true; + SetDirty(); } private void SetSpecies(string newSpecies) @@ -748,20 +773,20 @@ namespace Content.Client.Preferences.UI CMarkings.SetSpecies(newSpecies); // Repopulate the markings tab as well. UpdateSexControls(); // update sex for new species UpdateSpeciesGuidebookIcon(); - IsDirty = true; + SetDirty(); UpdatePreview(); } private void SetName(string newName) { Profile = Profile?.WithName(newName); - IsDirty = true; + SetDirty(); } private void SetSpawnPriority(SpawnPriorityPreference newSpawnPriority) { Profile = Profile?.WithSpawnPriorityPreference(newSpawnPriority); - IsDirty = true; + SetDirty(); } public void Save() @@ -773,6 +798,8 @@ namespace Content.Client.Preferences.UI _preferencesManager.UpdateCharacter(Profile, CharacterSlot); OnProfileChanged?.Invoke(Profile, CharacterSlot); + // Reset profile to default. + UserInterfaceManager.GetUIController().UpdateProfile(); } private bool IsDirty @@ -1065,7 +1092,7 @@ namespace Content.Client.Preferences.UI if (Profile is null) return; - UserInterfaceManager.GetUIController().UpdateCharacterUI(); + UserInterfaceManager.GetUIController().ReloadProfile(); SetPreviewRotation(_previewRotation); } diff --git a/Content.Client/Preferences/UI/RequirementsSelector.cs b/Content.Client/Preferences/UI/RequirementsSelector.cs index 97c75f3380..e016661ee6 100644 --- a/Content.Client/Preferences/UI/RequirementsSelector.cs +++ b/Content.Client/Preferences/UI/RequirementsSelector.cs @@ -153,7 +153,7 @@ public abstract class RequirementsSelector : BoxContainer where T : IPrototyp _loadout.EnsureValid(session, collection); _loadoutWindow.RefreshLoadouts(_loadout, session, collection); var controller = UserInterfaceManager.GetUIController(); - controller.UpdateCharacterUI(); + controller.ReloadProfile(); LoadoutUpdated?.Invoke(_loadout); }; @@ -165,7 +165,7 @@ public abstract class RequirementsSelector : BoxContainer where T : IPrototyp _loadout.EnsureValid(session, collection); _loadoutWindow.RefreshLoadouts(_loadout, session, collection); var controller = UserInterfaceManager.GetUIController(); - controller.UpdateCharacterUI(); + controller.ReloadProfile(); LoadoutUpdated?.Invoke(_loadout); }; diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 3f3521fda6..bd2a7f329a 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -315,6 +315,7 @@ namespace Content.Shared.Preferences list.Remove(antagId); } } + return new(this, _jobPriorities, list, _traitPreferences, _loadouts); } @@ -565,6 +566,23 @@ namespace Content.Shared.Preferences _loadouts[loadout.Role.Id] = loadout; } + public HumanoidCharacterProfile WithLoadout(RoleLoadout loadout) + { + // Deep copies so we don't modify the DB profile. + var copied = new Dictionary(); + + foreach (var proto in _loadouts) + { + if (proto.Key == loadout.Role) + continue; + + copied[proto.Key] = proto.Value.Clone(); + } + + copied[loadout.Role] = loadout.Clone(); + return new(this, _jobPriorities, _antagPreferences, _traitPreferences, copied); + } + public RoleLoadout GetLoadoutOrDefault(string id, IEntityManager entManager, IPrototypeManager protoManager) { if (!_loadouts.TryGetValue(id, out var loadout)) diff --git a/Content.Shared/Preferences/Loadouts/RoleLoadout.cs b/Content.Shared/Preferences/Loadouts/RoleLoadout.cs index 78cd376c85..e1c6f8395d 100644 --- a/Content.Shared/Preferences/Loadouts/RoleLoadout.cs +++ b/Content.Shared/Preferences/Loadouts/RoleLoadout.cs @@ -29,6 +29,18 @@ public sealed class RoleLoadout Role = role; } + public RoleLoadout Clone() + { + var weh = new RoleLoadout(Role); + + foreach (var selected in SelectedLoadouts) + { + weh.SelectedLoadouts.Add(selected.Key, new List(selected.Value)); + } + + return weh; + } + /// /// Ensures all prototypes exist and effects can be applied. /// -- 2.52.0