diff --git a/Content.Client/ClientPreferencesManager.cs b/Content.Client/ClientPreferencesManager.cs index e1e35704aa..e964e09960 100644 --- a/Content.Client/ClientPreferencesManager.cs +++ b/Content.Client/ClientPreferencesManager.cs @@ -26,6 +26,7 @@ namespace Content.Client HandlePreferencesAndSettings); _netManager.RegisterNetMessage(nameof(MsgUpdateCharacter)); _netManager.RegisterNetMessage(nameof(MsgSelectCharacter)); + _netManager.RegisterNetMessage(nameof(MsgDeleteCharacter)); } public void SelectCharacter(ICharacterProfile profile) @@ -54,7 +55,12 @@ namespace Content.Client public void CreateCharacter(ICharacterProfile profile) { - UpdateCharacter(profile, Preferences.FirstEmptySlot); + var characters = Preferences.Characters.ToList(); + + characters.Add(profile); + Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex); + + UpdateCharacter(profile, characters.Count - 1); } public void DeleteCharacter(ICharacterProfile profile) @@ -64,7 +70,11 @@ namespace Content.Client public void DeleteCharacter(int slot) { - UpdateCharacter(null, slot); + var characters = Preferences.Characters.Where((profile, index) => index != slot).ToArray(); + Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex); + var msg = _netManager.CreateNetMessage(); + msg.Slot = slot; + _netManager.ClientSendMessage(msg); } private void HandlePreferencesAndSettings(MsgPreferencesAndSettings message) diff --git a/Content.Server/Database/ServerDbManager.cs b/Content.Server/Database/ServerDbManager.cs index 39ffdf39f6..b0bab0e8e7 100644 --- a/Content.Server/Database/ServerDbManager.cs +++ b/Content.Server/Database/ServerDbManager.cs @@ -27,7 +27,7 @@ namespace Content.Server.Database // Preferences Task InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile); Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index); - Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile profile, int slot); + Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot); Task GetPlayerPreferencesAsync(NetUserId userId); // Username assignment (for guest accounts, so they persist GUID) @@ -90,7 +90,7 @@ namespace Content.Server.Database return _db.SaveSelectedCharacterIndexAsync(userId, index); } - public Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile profile, int slot) + public Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot) { return _db.SaveCharacterSlotAsync(userId, profile, slot); } diff --git a/Content.Server/Preferences/ServerPreferencesManager.cs b/Content.Server/Preferences/ServerPreferencesManager.cs index 209ee4afb1..755d3c9f96 100644 --- a/Content.Server/Preferences/ServerPreferencesManager.cs +++ b/Content.Server/Preferences/ServerPreferencesManager.cs @@ -42,6 +42,8 @@ namespace Content.Server.Preferences HandleSelectCharacterMessage); _netManager.RegisterNetMessage(nameof(MsgUpdateCharacter), HandleUpdateCharacterMessage); + _netManager.RegisterNetMessage(nameof(MsgDeleteCharacter), + HandleDeleteCharacterMessage); } @@ -77,6 +79,13 @@ namespace Content.Server.Preferences var profile = message.Profile; var userId = message.MsgChannel.UserId; + if (profile == null) + { + Logger.WarningS("prefs", + $"User {userId} sent a {nameof(MsgUpdateCharacter)} with a null profile in slot {slot}."); + return; + } + if (!_cachedPlayerPrefs.TryGetValue(userId, out var prefsData) || !prefsData.PrefsLoaded.IsCompleted) { Logger.WarningS("prefs", $"User {userId} tried to modify preferences before they loaded."); @@ -103,6 +112,35 @@ namespace Content.Server.Preferences } } + private async void HandleDeleteCharacterMessage(MsgDeleteCharacter message) + { + var slot = message.Slot; + var userId = message.MsgChannel.UserId; + + if (!_cachedPlayerPrefs.TryGetValue(userId, out var prefsData) || !prefsData.PrefsLoaded.IsCompleted) + { + Logger.WarningS("prefs", $"User {userId} tried to modify preferences before they loaded."); + return; + } + + if (slot < 0 || slot >= MaxCharacterSlots) + { + return; + } + + var curPrefs = prefsData.Prefs!; + + var arr = new ICharacterProfile[MaxCharacterSlots]; + curPrefs.Characters.Where((profile, index) => index != slot).ToArray().CopyTo(arr, 0); + + prefsData.Prefs = new PlayerPreferences(arr, slot); + + if (ShouldStorePrefs(message.MsgChannel.AuthType)) + { + await _db.SaveCharacterSlotAsync(message.MsgChannel.UserId, null, message.Slot); + } + } + public async void OnClientConnected(IPlayerSession session) { if (!ShouldStorePrefs(session.ConnectedClient.AuthType)) diff --git a/Content.Shared/Preferences/PlayerPreferences.cs b/Content.Shared/Preferences/PlayerPreferences.cs index bf044d0d99..630ceae22d 100644 --- a/Content.Shared/Preferences/PlayerPreferences.cs +++ b/Content.Shared/Preferences/PlayerPreferences.cs @@ -41,11 +41,20 @@ namespace Content.Shared.Preferences /// public ICharacterProfile SelectedCharacter => Characters.ElementAtOrDefault(SelectedCharacterIndex); - public int FirstEmptySlot => IndexOfCharacter(null); + public int FirstEmptySlot() + { + var firstEmpty = IndexOfCharacter(null); + return firstEmpty == -1 ? _characters.Count : firstEmpty; + } public int IndexOfCharacter(ICharacterProfile profile) { return _characters.FindIndex(x => x == profile); } + + public bool TryIndexOfCharacter(ICharacterProfile profile, out int index) + { + return (index = IndexOfCharacter(profile)) != -1; + } } } diff --git a/Content.Shared/Preferences/SharedPreferencesManager.cs b/Content.Shared/Preferences/SharedPreferencesManager.cs index 4d7180794d..2e1c0f20ad 100644 --- a/Content.Shared/Preferences/SharedPreferencesManager.cs +++ b/Content.Shared/Preferences/SharedPreferencesManager.cs @@ -128,5 +128,32 @@ namespace Content.Shared.Preferences } } } + + /// + /// The client sends this to delete a character profile. + /// + protected class MsgDeleteCharacter : NetMessage + { + #region REQUIRED + + public const MsgGroups GROUP = MsgGroups.Command; + public const string NAME = nameof(MsgDeleteCharacter); + + public MsgDeleteCharacter(INetChannel channel) : base(NAME, GROUP) { } + + #endregion + + public int Slot; + + public override void ReadFromBuffer(NetIncomingMessage buffer) + { + Slot = buffer.ReadInt32(); + } + + public override void WriteToBuffer(NetOutgoingMessage buffer) + { + buffer.Write(Slot); + } + } } }