diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index 582f3160e2..dbc1cc1231 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -39,21 +39,22 @@ namespace Content.Server.Database { await using var db = await GetDb(); - var prefs = await db.DbContext.Preference.SingleAsync(p => p.UserId == userId.UserId); - prefs.SelectedCharacterSlot = index; + await SetSelectedCharacterSlotAsync(userId, index, db.DbContext); await db.DbContext.SaveChangesAsync(); } public async Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot) { + await using var db = await GetDb(); + if (profile is null) { - await DeleteCharacterSlotAsync(userId, slot); + DeleteCharacterSlot(db.DbContext, userId, slot); + await db.DbContext.SaveChangesAsync(); return; } - await using var db = await GetDb(); if (!(profile is HumanoidCharacterProfile humanoid)) { // TODO: Handle other ICharacterProfile implementations properly @@ -80,17 +81,12 @@ namespace Content.Server.Database await db.DbContext.SaveChangesAsync(); } - private async Task DeleteCharacterSlotAsync(NetUserId userId, int slot) + private static void DeleteCharacterSlot(ServerDbContext db, NetUserId userId, int slot) { - await using var db = await GetDb(); - - db.DbContext - .Preference + db.Preference .Single(p => p.UserId == userId.UserId) .Profiles .RemoveAll(h => h.Slot == slot); - - await db.DbContext.SaveChangesAsync(); } public async Task InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile) @@ -113,6 +109,22 @@ namespace Content.Server.Database return new PlayerPreferences(new[] {new KeyValuePair(0, defaultProfile)}, 0); } + public async Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot) + { + await using var db = await GetDb(); + + DeleteCharacterSlot(db.DbContext, userId, deleteSlot); + await SetSelectedCharacterSlotAsync(userId, newSlot, db.DbContext); + + await db.DbContext.SaveChangesAsync(); + } + + private static async Task SetSelectedCharacterSlotAsync(NetUserId userId, int newSlot, ServerDbContext db) + { + var prefs = await db.Preference.SingleAsync(p => p.UserId == userId.UserId); + prefs.SelectedCharacterSlot = newSlot; + } + private static HumanoidCharacterProfile ConvertProfiles(Profile profile) { var jobs = profile.Jobs.ToDictionary(j => j.JobName, j => (JobPriority) j.Priority); @@ -188,6 +200,7 @@ namespace Content.Server.Database await db.DbContext.SaveChangesAsync(); } + /* * BAN STUFF */ diff --git a/Content.Server/Database/ServerDbManager.cs b/Content.Server/Database/ServerDbManager.cs index b0bab0e8e7..8d7dc816c4 100644 --- a/Content.Server/Database/ServerDbManager.cs +++ b/Content.Server/Database/ServerDbManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Net; using System.Threading.Tasks; @@ -28,6 +28,8 @@ namespace Content.Server.Database Task InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile); Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index); Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot); + // Single method for two operations for transaction. + Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot); Task GetPlayerPreferencesAsync(NetUserId userId); // Username assignment (for guest accounts, so they persist GUID) @@ -95,6 +97,11 @@ namespace Content.Server.Database return _db.SaveCharacterSlotAsync(userId, profile, slot); } + public Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot) + { + return _db.DeleteSlotAndSetSelectedIndex(userId, deleteSlot, newSlot); + } + public Task GetPlayerPreferencesAsync(NetUserId userId) { return _db.GetPlayerPreferencesAsync(userId); diff --git a/Content.Server/Preferences/ServerPreferencesManager.cs b/Content.Server/Preferences/ServerPreferencesManager.cs index 11d2e45e2c..e9428a99e0 100644 --- a/Content.Server/Preferences/ServerPreferencesManager.cs +++ b/Content.Server/Preferences/ServerPreferencesManager.cs @@ -131,14 +131,36 @@ namespace Content.Server.Preferences var curPrefs = prefsData.Prefs!; + // If they try to delete the slot they have selected then we switch to another one. + // Of course, that's only if they HAVE another slot. + int? nextSlot = null; + if (curPrefs.SelectedCharacterIndex == slot) + { + var (ns, profile) = curPrefs.Characters.FirstOrDefault(p => p.Key != message.Slot); + if (profile == null) + { + // Only slot left, can't delete. + return; + } + + nextSlot = ns; + } + var arr = new Dictionary(curPrefs.Characters); arr.Remove(slot); - prefsData.Prefs = new PlayerPreferences(arr, slot); + prefsData.Prefs = new PlayerPreferences(arr, nextSlot ?? curPrefs.SelectedCharacterIndex); if (ShouldStorePrefs(message.MsgChannel.AuthType)) { - await _db.SaveCharacterSlotAsync(message.MsgChannel.UserId, null, message.Slot); + if (nextSlot != null) + { + await _db.DeleteSlotAndSetSelectedIndex(userId, slot, nextSlot.Value); + } + else + { + await _db.SaveCharacterSlotAsync(userId, null, slot); + } } }