diff --git a/.editorconfig b/.editorconfig index 467b2ac..eaa2b69 100644 --- a/.editorconfig +++ b/.editorconfig @@ -25,4 +25,7 @@ dotnet_diagnostic.CS8603.severity = none dotnet_diagnostic.SYSLIB0039.severity = none # CS0219: 变量已被赋值,但从未使用过它的值 -dotnet_diagnostic.CS0219.severity = none \ No newline at end of file +dotnet_diagnostic.CS0219.severity = none + +# CS8618: 类型不包含 null 值的属性 +dotnet_diagnostic.CS8618.severity = none \ No newline at end of file diff --git a/EpinelPS/Data/GameData.cs b/EpinelPS/Data/GameData.cs index 72399de..dc9a04f 100644 --- a/EpinelPS/Data/GameData.cs +++ b/EpinelPS/Data/GameData.cs @@ -308,6 +308,16 @@ namespace EpinelPS.Data public readonly Dictionary SimulationRoomBuffPreviewTable = []; [LoadRecord("SimulationRoomBuffTable.json", "Id")] public readonly Dictionary SimulationRoomBuffTable = []; + + // SimulationRoom Overclock Data Tables + [LoadRecord("SimulationRoomOcLevelTable.json", "Id")] + public readonly Dictionary SimulationRoomOcLevelTable = []; + [LoadRecord("SimulationRoomOcOptionGroupTable.json", "Id")] + public readonly Dictionary SimulationRoomOcOptionGroupTable = []; + [LoadRecord("SimulationRoomOcOptionTable.json", "Id")] + public readonly Dictionary SimulationRoomOcOptionTable = []; + [LoadRecord("SimulationRoomOcSeasonTable.json", "Id")] + public readonly Dictionary SimulationRoomOcSeasonTable = []; static async Task BuildAsync() { @@ -350,8 +360,9 @@ namespace EpinelPS.Data { using FileStream fileStream = File.Open(file, FileMode.Open, FileAccess.Read); - Rfc2898DeriveBytes a = new(PresharedValue, data.GetSalt2Bytes(), 10000, HashAlgorithmName.SHA256); - byte[] key2 = a.GetBytes(32); + // Rfc2898DeriveBytes a = new(PresharedValue, data.GetSalt2Bytes(), 10000, HashAlgorithmName.SHA256); + // byte[] key2 = a.GetBytes(32); + byte[] key2 = Rfc2898DeriveBytes.Pbkdf2(PresharedValue, data.GetSalt2Bytes(), 10000, HashAlgorithmName.SHA256, 32); byte[] decryptionKey = key2[0..16]; byte[] iv = key2[16..32]; @@ -387,8 +398,9 @@ namespace EpinelPS.Data throw new Exception("error 3"); dataMs.Position = 0; - Rfc2898DeriveBytes keyDec2 = new(PresharedValue, data.GetSalt1Bytes(), 10000, HashAlgorithmName.SHA256); - byte[] key3 = keyDec2.GetBytes(32); + // Rfc2898DeriveBytes keyDec2 = new(PresharedValue, data.GetSalt1Bytes(), 10000, HashAlgorithmName.SHA256); + // byte[] key3 = keyDec2.GetBytes(32); + byte[] key3 = Rfc2898DeriveBytes.Pbkdf2(PresharedValue, data.GetSalt1Bytes(), 10000, HashAlgorithmName.SHA256, 32); byte[] val2 = key3[0..16]; byte[] iv2 = key3[16..32]; diff --git a/EpinelPS/LobbyServer/Character/GetCharacterData.cs b/EpinelPS/LobbyServer/Character/GetCharacterData.cs index c2eb4e5..87b33fd 100644 --- a/EpinelPS/LobbyServer/Character/GetCharacterData.cs +++ b/EpinelPS/LobbyServer/Character/GetCharacterData.cs @@ -13,7 +13,27 @@ namespace EpinelPS.LobbyServer.Character ResGetCharacterData response = new(); foreach (CharacterModel item in user.Characters) { - response.Character.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Lv = user.GetCharacterLevel(item.Csn, item.Level), Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel }, IsSynchro = user.GetSynchro(item.Csn) }); + response.Character.Add(new NetUserCharacterData() + { + Default = new() + { + Csn = item.Csn, + Skill1Lv = item.Skill1Lvl, + Skill2Lv = item.Skill2Lvl, + CostumeId = item.CostumeId, + Lv = user.GetCharacterLevel(item.Csn, item.Level), + Grade = item.Grade, + Tid = item.Tid, + UltiSkillLv = item.UltimateLevel + }, + IsSynchro = user.GetSynchro(item.Csn) + }); + + // Check if character is main force + if (item.IsMainForce) + { + response.MainForceCsnList.Add(item.Csn); + } } List highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)]; diff --git a/EpinelPS/LobbyServer/Character/SetCharacterMainForce.cs b/EpinelPS/LobbyServer/Character/SetCharacterMainForce.cs new file mode 100644 index 0000000..2361adf --- /dev/null +++ b/EpinelPS/LobbyServer/Character/SetCharacterMainForce.cs @@ -0,0 +1,29 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Character +{ + [PacketPath("/character/mainforce/set")] + public class SetCharacterMainForce : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + ReqSetCharacterMainForce req = await ReadData(); + User user = GetUser(); + + foreach (CharacterModel item in user.Characters) + { + if (item.Csn == req.Csn) + { + item.IsMainForce = req.IsMainForce; + break; + } + } + JsonDb.Save(); + + ResSetCharacterMainForce response = new(); + + await WriteDataAsync(response); + } + } +} diff --git a/EpinelPS/LobbyServer/ContentsOpen/GetUnlocked.cs b/EpinelPS/LobbyServer/ContentsOpen/GetUnlocked.cs index b54b9d8..6022d7c 100644 --- a/EpinelPS/LobbyServer/ContentsOpen/GetUnlocked.cs +++ b/EpinelPS/LobbyServer/ContentsOpen/GetUnlocked.cs @@ -31,7 +31,7 @@ namespace EpinelPS.LobbyServer.ContentsOpen JsonDb.Save(); } - foreach (KeyValuePair item in user.ContentsOpenUnlocked) + foreach (KeyValuePair item in user.ContentsOpenUnlocked.OrderBy(x => x.Key)) { response.ContentsOpenUnlockInfoList.Add(new NetContentsOpenUnlockInfo() { diff --git a/EpinelPS/LobbyServer/LobbyUser/GetContentsData.cs b/EpinelPS/LobbyServer/LobbyUser/GetContentsData.cs index 0b98582..4a83669 100644 --- a/EpinelPS/LobbyServer/LobbyUser/GetContentsData.cs +++ b/EpinelPS/LobbyServer/LobbyUser/GetContentsData.cs @@ -1,4 +1,5 @@ -using EpinelPS.Utils; +using EpinelPS.Data; +using EpinelPS.Utils; namespace EpinelPS.LobbyServer.LobbyUser { @@ -7,12 +8,12 @@ namespace EpinelPS.LobbyServer.LobbyUser { protected override async Task HandleAsync() { - ReqGetContentsOpenData req = await ReadData(); + await ReadData(); User user = GetUser(); // this request returns a list of "special" stages that mark when something is unlocked, ex: the shop or interception - List specialStages = [6003003, 6002008, 6002016, 6005003, 6003021, 6011018, 6007021, 6004018, 6005013, 6003009, 6003012, 6009017, 6016039, 6001004, 6000003, 6000001, 6002001, 6004023, 6005026, 6020050, 6006004, 6006023,6022049]; + List specialStages = [6003003, 6002008, 6002016, 6005003, 6003021, 6011018, 6007021, 6004018, 6005013, 6003009, 6003012, 6009017, 6016039, 6001004, 6000003, 6000001, 6002001, 6004023, 6005026, 6020050, 6006004, 6006023, 6022049]; ResGetContentsOpenData response = new(); foreach (FieldInfoNew field in user.FieldInfoNew.Values) @@ -23,12 +24,40 @@ namespace EpinelPS.LobbyServer.LobbyUser response.ClearStageList.Add(stage); } } - response.MaxGachaCount = 10; - response.MaxGachaPremiumCount = 10; + response.MaxGachaCount = user.GachaTutorialPlayCount; + response.MaxGachaPremiumCount = user.GachaTutorialPlayCount; // todo tutorial playcount of gacha response.TutorialGachaPlayCount = user.GachaTutorialPlayCount; + // ClearSimRoomChapterList: 已通关的章节列表,用于显示超频选项 SimRoomOC + response.ClearSimRoomChapterList.AddRange(GetClearSimRoomChapterList(user)); + await WriteDataAsync(response); } + + private static List GetClearSimRoomChapterList(User user) + { + var clearSimRoomChapterList = new List(); + try + { + var currentDifficulty = user.ResetableData.SimRoomData?.CurrentDifficulty ?? 0; + var currentChapter = user.ResetableData.SimRoomData?.CurrentChapter ?? 0; + if (currentDifficulty > 0 && currentChapter > 0) + { + var chapters = GameData.Instance.SimulationRoomChapterTable.Values.Where(c => c.DifficultyId <= currentDifficulty).ToList(); + foreach (var chapter in chapters) + { + bool isAdd = chapter.DifficultyId < currentDifficulty || + (chapter.DifficultyId == currentDifficulty && chapter.Chapter <= currentChapter); + if (isAdd) clearSimRoomChapterList.Add(chapter.Id); + } + } + } + catch (Exception e) + { + Logging.Warn($"GetClearSimRoomChapterList error: {e.Message}"); + } + return clearSimRoomChapterList; + } } } diff --git a/EpinelPS/LobbyServer/LobbyUser/GetUserTitleCounter.cs b/EpinelPS/LobbyServer/LobbyUser/GetUserTitleCounter.cs index c61b72c..d48f3ac 100644 --- a/EpinelPS/LobbyServer/LobbyUser/GetUserTitleCounter.cs +++ b/EpinelPS/LobbyServer/LobbyUser/GetUserTitleCounter.cs @@ -7,11 +7,16 @@ namespace EpinelPS.LobbyServer.LobbyUser { protected override async Task HandleAsync() { - ReqGetUserTitleCounterList req = await ReadData(); + await ReadData(); - ResGetUserTitleCounterList r = new(); + ResGetUserTitleCounterList response = new(); + response.UserTitleCounterList.Add(new ResGetUserTitleCounterList.Types.NetUserTitleCounter { Condition = 23, SubCondition = 1, Count = 10}); + response.UserTitleCounterList.Add(new ResGetUserTitleCounterList.Types.NetUserTitleCounter { Condition = 23, SubCondition = 2, Count = 10}); + response.UserTitleCounterList.Add(new ResGetUserTitleCounterList.Types.NetUserTitleCounter { Condition = 23, SubCondition = 3, Count = 10}); + response.UserTitleCounterList.Add(new ResGetUserTitleCounterList.Types.NetUserTitleCounter { Condition = 23, SubCondition = 4, Count = 10}); + response.UserTitleCounterList.Add(new ResGetUserTitleCounterList.Types.NetUserTitleCounter { Condition = 23, SubCondition = 5, Count = 10}); - await WriteDataAsync(r); + await WriteDataAsync(response); } } } diff --git a/EpinelPS/LobbyServer/Simroom/GetAcquireBuffFunction.cs b/EpinelPS/LobbyServer/Simroom/GetAcquireBuffFunction.cs new file mode 100644 index 0000000..1ece407 --- /dev/null +++ b/EpinelPS/LobbyServer/Simroom/GetAcquireBuffFunction.cs @@ -0,0 +1,44 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Simroom +{ + [PacketPath("/simroom/getacquirebufffunction")] + public class GetAcquireBuffFunction : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + // ReqGetSimRoomAcquireBuffFunction Fields + // NetSimRoomEventLocationInfo Location + // int Event + // int SelectionNumber + // int SelectionGroupElementId + // { "location": { "chapter": 3, "stage": 6, "order": 2 }, "event": 22103, "selectionNumber": 2, "selectionGroupElementId": 221033 } + var req = await ReadData(); + var user = GetUser(); + + // ResGetSimRoomAcquireBuffFunction Fields + // SimRoomResult Result + // int RandomBuff + ResGetSimRoomAcquireBuffFunction response = new() + { + Result = SimRoomResult.Success, + RandomBuff = 2020406 + }; + // Update + var location = req.Location; + // Check + var events = user.ResetableData.SimRoomData.Events; + var simRoomEventIndex = events.FindIndex(x => x.Location.Chapter == location.Chapter && x.Location.Stage == location.Stage && x.Location.Order == location.Order); + if (simRoomEventIndex < 0) + { + Logging.Warn("Not Fond UserSimRoomEvent"); + await WriteDataAsync(response); + } + SimRoomHelper.UpdateUserSimRoomEvent(user, index: simRoomEventIndex, events: events, selectionNumber: req.SelectionNumber, isDone: true); + JsonDb.Save(); + + await WriteDataAsync(response); + } + } +} \ No newline at end of file diff --git a/EpinelPS/LobbyServer/Simroom/GetSimRoomData.cs b/EpinelPS/LobbyServer/Simroom/GetSimRoomData.cs index f8d0163..b6839c2 100644 --- a/EpinelPS/LobbyServer/Simroom/GetSimRoomData.cs +++ b/EpinelPS/LobbyServer/Simroom/GetSimRoomData.cs @@ -31,6 +31,8 @@ namespace EpinelPS.LobbyServer.Simroom var CurrentDifficulty = user.ResetableData.SimRoomData.CurrentDifficulty; var currentChapter = user.ResetableData.SimRoomData.CurrentChapter; + var buffs = user.ResetableData.SimRoomData.Buffs; + var legacyBuffs = user.ResetableData.SimRoomData.LegacyBuffs; ResGetSimRoom response = new() { @@ -41,20 +43,34 @@ namespace EpinelPS.LobbyServer.Simroom // NextLegacyBuffResetDate: Resets at 2 AM every Tuesday NextLegacyBuffResetDate = DateTimeHelper.GetNextWeekdayAtTime("China Standard Time", DayOfWeek.Tuesday, 2).ToTimestamp(), IsSimpleModeSkipEnabled = user.ResetableData.SimRoomData.IsSimpleModeSkipEnabled, - + LastPlayedChapter = new NetSimRoomChapterInfo() + { + Chapter = currentChapter, + Difficulty = CurrentDifficulty, + } }; // LegacyBuffs - response.LegacyBuffs.AddRange(user.ResetableData.SimRoomData.LegacyBuffs); + response.LegacyBuffs.AddRange(legacyBuffs); // OverclockData - response.OverclockData = GetOverclockData(user: user); + try + { + response.OverclockData = GetOverclockData(user: user); + } + catch (Exception ex) + { + Logging.WriteLine($"Get OverclockData Exception: {ex.Message}", LogType.Error); + } // ClearInfos response.ClearInfos.AddRange(GetClearInfos(user)); // OverclockOptionList - // response.OverclockOptionList.Add([]); + if (user.ResetableData.SimRoomData.CurrentSeasonData.IsOverclock) + { + response.OverclockOptionList.AddRange(user.ResetableData.SimRoomData.CurrentSeasonData.CurrentOptionList); + } // check if user is in sim room if (user.ResetableData.SimRoomData.Entered) @@ -65,15 +81,9 @@ namespace EpinelPS.LobbyServer.Simroom // TODO: Get RemainingHps response.RemainingHps.AddRange(GetCharacterHp(user)); - response.LastPlayedChapter = new NetSimRoomChapterInfo() - { - Chapter = currentChapter, - Difficulty = CurrentDifficulty, - }; - // Buffs = Buffs + LegacyBuffs - response.Buffs.AddRange(user.ResetableData.SimRoomData.Buffs); - response.Buffs.AddRange(user.ResetableData.SimRoomData.LegacyBuffs); + response.Buffs.AddRange(buffs); + response.Buffs.AddRange(legacyBuffs); // response.NextSimpleModeBuffSelectionInfo = new() // { @@ -144,57 +154,66 @@ namespace EpinelPS.LobbyServer.Simroom public static List GetCharacterHp(User user) { List hps = []; - if (user.UserTeams.TryGetValue((int)TeamType.SimulationRoom, out var userTeamData)) + var userRemainingHps = user.ResetableData.SimRoomData.RemainingHps; + foreach (var userRemainingHp in userRemainingHps) { - if (userTeamData.Teams.Count > 0 && userTeamData.Teams[0].Slots.Count > 0) - { - foreach (var slot in userTeamData.Teams[0].Slots) - { - hps.Add(new() { Csn = slot.Value, Hp = 100000 }); - } - } + hps.Add(new() { Csn = userRemainingHp.Csn, Hp = userRemainingHp.Hp }); } return hps; } private static NetSimRoomOverclockData GetOverclockData(User user) { - return new NetSimRoomOverclockData + var currentSeasonData = user.ResetableData.SimRoomData.CurrentSeasonData; + + var netOverclockData = new NetSimRoomOverclockData { + HasClearedLevel50 = currentSeasonData.HasClearedLevel50, + WasInfinitePopupChecked = currentSeasonData.WasInfinitePopupChecked, + WasMainSeasonResetPopupChecked = currentSeasonData.WasMainSeasonResetPopupChecked, + WasSubSeasonResetPopupChecked = currentSeasonData.WasSubSeasonResetPopupChecked, + + // CurrentSeasonData CurrentSeasonData = new NetSimRoomOverclockSeasonData { - SeasonStartDate = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(-1)), - SeasonEndDate = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(7)), + SeasonStartDate = DateTime.UtcNow.Date.AddDays(-2).ToTimestamp(), + SeasonEndDate = DateTime.UtcNow.Date.AddDays(12).ToTimestamp(), IsSeasonOpen = true, - Season = 1, - SubSeason = 1, - SeasonWeekCount = 1 + Season = currentSeasonData.CurrentSeason, + SubSeason = currentSeasonData.CurrentSubSeason, + SeasonWeekCount = 2, }, + // CurrentSeasonHighScore CurrentSeasonHighScore = new NetSimRoomOverclockHighScoreData { - CreatedAt = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(-1)), - OptionLevel = 1, - Season = 1, - SubSeason = 1, - OptionList = { 1 } + CreatedAt = currentSeasonData.CurrentSeasonHighScore.CreatedAt ?? DateTime.UtcNow.Date.AddDays(-2).ToTimestamp(), + Season = currentSeasonData.CurrentSeasonHighScore.Season, + SubSeason = currentSeasonData.CurrentSeasonHighScore.SubSeason, + OptionList = { currentSeasonData.CurrentSeasonHighScore.OptionList }, + OptionLevel = currentSeasonData.CurrentSeasonHighScore.OptionLevel, }, - + // CurrentSubSeasonHighScore CurrentSubSeasonHighScore = new NetSimRoomOverclockHighScoreData { - CreatedAt = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(-1)), - OptionLevel = 1, - Season = 1, - SubSeason = 1, - OptionList = { 1 } + CreatedAt = currentSeasonData.CurrentSubSeasonHighScore.CreatedAt ?? DateTime.UtcNow.Date.AddDays(-2).ToTimestamp(), + Season = currentSeasonData.CurrentSubSeasonHighScore.Season, + SubSeason = currentSeasonData.CurrentSubSeasonHighScore.SubSeason, + OptionList = { currentSeasonData.CurrentSubSeasonHighScore.OptionList }, + OptionLevel = currentSeasonData.CurrentSubSeasonHighScore.OptionLevel, }, + // LatestOption LatestOption = new NetSimRoomOverclockOptionSettingData { - Season = 1, - OptionList = { 1 } + Season = currentSeasonData.LatestOption.Season, + OptionList = { currentSeasonData.LatestOption.OptionList }, } }; + netOverclockData.CurrentSeasonData.Season = GameData.Instance.SimulationRoomOcSeasonTable.Keys.Max(); + netOverclockData.CurrentSeasonData.SubSeason = 3; + + return netOverclockData; } } } diff --git a/EpinelPS/LobbyServer/Simroom/InfinitePopupCheck.cs b/EpinelPS/LobbyServer/Simroom/InfinitePopupCheck.cs new file mode 100644 index 0000000..4ed45bf --- /dev/null +++ b/EpinelPS/LobbyServer/Simroom/InfinitePopupCheck.cs @@ -0,0 +1,22 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Simroom +{ + [PacketPath("/simroom/popup-check/infinite")] + public class InfinitePopupCheck : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + var user = GetUser(); + + ResInfinitePopupCheck response = new(); + + user.ResetableData.SimRoomData.CurrentSeasonData.WasInfinitePopupChecked = true; + JsonDb.Save(); + + await WriteDataAsync(response); + } + } +} \ No newline at end of file diff --git a/EpinelPS/LobbyServer/Simroom/ProceedSkipFunction.cs b/EpinelPS/LobbyServer/Simroom/ProceedSkipFunction.cs new file mode 100644 index 0000000..98199b5 --- /dev/null +++ b/EpinelPS/LobbyServer/Simroom/ProceedSkipFunction.cs @@ -0,0 +1,40 @@ +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Simroom +{ + [PacketPath("/simroom/proceedskipfunction")] + public class ProceedSkipFunction : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + // { "location": { "chapter": 3, "stage": 6, "order": 2 }, "event": 21060, "selectionNumber": 2, "selectionGroupElementId": 210602 } + var req = await ReadData(); + // ReqProceedSimRoomSkipFunction Fields + // NetSimRoomEventLocationInfo location, + // int event, + // int selectionNumber, + // int selectionGroupElementId, + User user = GetUser(); + // ResProceedSimRoomSkipFunction Fields + // SimRoomResult Result, + ResProceedSimRoomSkipFunction response = new() + { + Result = SimRoomResult.Success + }; + + // Update + var location = req.Location; + // Check + var events = user.ResetableData.SimRoomData.Events; + var simRoomEventIndex = events.FindIndex(x => x.Location.Chapter == location.Chapter && x.Location.Stage == location.Stage && x.Location.Order == location.Order); + if (simRoomEventIndex < 0) + { + Logging.Warn("Not Fond UserSimRoomEvent"); + await WriteDataAsync(response); + } + SimRoomHelper.UpdateUserSimRoomEvent(user, index: simRoomEventIndex, events: events, selectionNumber: req.SelectionNumber, isDone: true); + + await WriteDataAsync(response); + } + } +} \ No newline at end of file diff --git a/EpinelPS/LobbyServer/Simroom/Quit.cs b/EpinelPS/LobbyServer/Simroom/Quit.cs index a1403ad..4de678e 100644 --- a/EpinelPS/LobbyServer/Simroom/Quit.cs +++ b/EpinelPS/LobbyServer/Simroom/Quit.cs @@ -45,6 +45,7 @@ namespace EpinelPS.LobbyServer.Simroom user.ResetableData.SimRoomData.Events = []; user.ResetableData.SimRoomData.RemainingHps = []; user.ResetableData.SimRoomData.Buffs = []; + user.ResetableData.SimRoomData.CurrentSeasonData.IsOverclock = false; JsonDb.Save(); diff --git a/EpinelPS/LobbyServer/Simroom/SelectBuff.cs b/EpinelPS/LobbyServer/Simroom/SelectBuff.cs index 6e2684b..4439238 100644 --- a/EpinelPS/LobbyServer/Simroom/SelectBuff.cs +++ b/EpinelPS/LobbyServer/Simroom/SelectBuff.cs @@ -60,6 +60,12 @@ namespace EpinelPS.LobbyServer.Simroom var difficulty = user.ResetableData.SimRoomData.CurrentDifficulty; var reward = SimRoomHelper.SimRoomReceivedReward(user, difficulty, location.Chapter); if (reward is not null) response.Reward = reward; + + var overclockReward = SimRoomHelper.SimRoomOverclockReceivedReward(user); + if (overclockReward is not null) response.RewardByOverclock = overclockReward; + + // Update User OverclockHighScoreData + SimRoomHelper.UpdateOverclockHighScoreData(user, req.Location); } } diff --git a/EpinelPS/LobbyServer/Simroom/SelectDifficulty.cs b/EpinelPS/LobbyServer/Simroom/SelectDifficulty.cs index b8d1494..a6a3526 100644 --- a/EpinelPS/LobbyServer/Simroom/SelectDifficulty.cs +++ b/EpinelPS/LobbyServer/Simroom/SelectDifficulty.cs @@ -20,9 +20,22 @@ namespace EpinelPS.LobbyServer.Simroom user.ResetableData.SimRoomData.Entered = true; user.ResetableData.SimRoomData.CurrentDifficulty = req.Difficulty; user.ResetableData.SimRoomData.CurrentChapter = req.StartingChapter; + // Update season data + bool isOverclock = req.OverclockOptionList is not null && req.OverclockOptionList.Count > 0 && req.OverclockSeason > 0 && req.OverclockSubSeason > 0; + var currentSeasonData = user.ResetableData.SimRoomData.CurrentSeasonData; + currentSeasonData.IsOverclock = isOverclock; + if (isOverclock) + { + currentSeasonData.CurrentSeason = req.OverclockSeason; + currentSeasonData.CurrentSubSeason = req.OverclockSubSeason; + currentSeasonData.CurrentOptionList = [.. req.OverclockOptionList]; + } + user.ResetableData.SimRoomData.CurrentSeasonData = currentSeasonData; JsonDb.Save(); - List events = SimRoomHelper.GetSimRoomEvents(user); + List events = SimRoomHelper.GetSimRoomEvents(user, req.Difficulty, req.StartingChapter, + [.. req.OverclockOptionList], req.OverclockSeason, req.OverclockSubSeason); + user.ResetableData.SimRoomData.Events = [.. events.Select(SimRoomHelper.NetToM)]; JsonDb.Save(); diff --git a/EpinelPS/LobbyServer/Simroom/SimRoomHelper.cs b/EpinelPS/LobbyServer/Simroom/SimRoomHelper.cs index 6424af0..37d63bb 100644 --- a/EpinelPS/LobbyServer/Simroom/SimRoomHelper.cs +++ b/EpinelPS/LobbyServer/Simroom/SimRoomHelper.cs @@ -1,6 +1,7 @@ using EpinelPS.Data; using EpinelPS.Database; using EpinelPS.Utils; +using Google.Protobuf.WellKnownTypes; using log4net; using Newtonsoft.Json; @@ -17,15 +18,32 @@ namespace EpinelPS.LobbyServer.Simroom /// User /// DifficultyId /// ChapterId + /// OverclockOptionList + /// OverclockSeason + /// OverclockSubSeason /// The list of NetSimRoomEvent - public static List GetSimRoomEvents(User user, int difficultyId = 0, int chapterId = 0) + public static List GetSimRoomEvents(User user, int difficultyId = 0, int chapterId = 0, + List? overclockOptionList = null, int overclockSeason = 0, int overclockSubSeason = 0) { + + bool isOverclock = overclockOptionList is not null && overclockOptionList.Count > 0 && overclockSeason > 0 && overclockSubSeason > 0; + List netSimRooms = []; + var currentOCData = user.ResetableData.SimRoomData.CurrentSeasonData; int currentDifficulty = user.ResetableData.SimRoomData.CurrentDifficulty; int currentChapter = user.ResetableData.SimRoomData.CurrentChapter; + int currentOCSeason = currentOCData.CurrentSeason; + int currentOCSubSeason = currentOCData.CurrentSubSeason; + List currentOCList = currentOCData.CurrentOptionList; if (difficultyId > 0) currentDifficulty = difficultyId; if (chapterId > 0) currentChapter = chapterId; + if (isOverclock) + { + currentOCSeason = overclockSeason; + currentOCSubSeason = overclockSubSeason; + currentOCList = overclockOptionList ?? []; + } var events = user.ResetableData.SimRoomData.Events; if (events.Count > 1) @@ -33,7 +51,8 @@ namespace EpinelPS.LobbyServer.Simroom return [.. events.Select(MToNet)]; } - var simRoomChapter = GameData.Instance.SimulationRoomChapterTable.Values.FirstOrDefault(x => x.Chapter == currentChapter && x.DifficultyId == currentDifficulty); + var simRoomChapter = GameData.Instance.SimulationRoomChapterTable.Values + .FirstOrDefault(x => x.Chapter == currentChapter && x.DifficultyId == currentDifficulty); log.Debug($"Fond SimulationRoomChapter Chapter: {currentChapter}, DifficultyId: {currentDifficulty} Data: {JsonConvert.SerializeObject(simRoomChapter)}"); var buffPreviewRecords = GameData.Instance.SimulationRoomBuffPreviewTable.Values.ToList(); @@ -43,13 +62,18 @@ namespace EpinelPS.LobbyServer.Simroom if (simRoomChapter is null) return netSimRooms; + int battleEventGroup = GetBattleEventGroup(overclockOptionList, isOverclock); + bool isHardBattle = GetIsHardBattle(overclockOptionList, isOverclock); + for (int i = 1; i <= simRoomChapter.StageValue; i++) { if (i == simRoomChapter.StageValue) // BossBattle { - var battleBuffPreviews = GameData.Instance.SimulationRoomBuffPreviewTable.Values.Where(x => x.EventType is SimulationRoomEvent.BossBattle).ToList(); + var battleBuffPreviews = GameData.Instance.SimulationRoomBuffPreviewTable.Values.Where(x => + x.EventType is SimulationRoomEvent.BossBattle).ToList(); var randomBuffPreview = GetRandomItems(battleBuffPreviews, 1); - var simRoomBattleEvent = CreateSimRoomBattleEvent(chapter: simRoomChapter, stage: i, order: 1, simRoomBattleEventRecords, randomBuffPreview[0]); + var simRoomBattleEvent = CreateSimRoomBattleEvent(simRoomChapter, i, 1, simRoomBattleEventRecords, randomBuffPreview[0], + overclockSeason: currentOCSeason, battleEventGroup: battleEventGroup, isOverclock); events.Add(NetToM(simRoomBattleEvent)); netSimRooms.Add(simRoomBattleEvent); } @@ -117,18 +141,26 @@ namespace EpinelPS.LobbyServer.Simroom { var battleBuffPreviews = buffPreviewRecords.FindAll(x => x.EventType is SimulationRoomEvent.NormalBattle or SimulationRoomEvent.EliteBattle); + if (isOverclock && isHardBattle) + { + battleBuffPreviews = buffPreviewRecords.FindAll(x + => x.EventType is SimulationRoomEvent.EliteBattle); + } var randomBuffPreview = GetRandomItems(battleBuffPreviews, 3); int order = 0; foreach (var simRoomBuffPreview in randomBuffPreview) { order += 1; - var simRoomBattleEvent = CreateSimRoomBattleEvent(chapter: simRoomChapter, stage: i, order: order, simRoomBattleEventRecords, simRoomBuffPreview); + var simRoomBattleEvent = CreateSimRoomBattleEvent(chapter: simRoomChapter, stage: i, order: order, + simRoomBattleEventRecords, simRoomBuffPreview, overclockSeason: currentOCSeason, battleEventGroup: battleEventGroup, isOverclock); events.Add(NetToM(simRoomBattleEvent)); netSimRooms.Add(simRoomBattleEvent); } } } - // user.AddTrigger() + user.AddTrigger(Trigger.SimulationRoomStart, value: 1); + user.AddTrigger(Trigger.SimulationRoomClearCount1Only, value: 1); + user.AddTrigger(Trigger.SimulationRoomClearWithoutCondition, value: 1); user.ResetableData.SimRoomData.Events = events; JsonDb.Save(); return netSimRooms; @@ -264,7 +296,8 @@ namespace EpinelPS.LobbyServer.Simroom /// /// NetSimRoomEvent private static NetSimRoomEvent CreateSimRoomBattleEvent(SimulationRoomChapterRecord chapter, int stage, int order, - List simRoomBattleEventRecords, SimulationRoomBuffPreviewRecord randomBuffPreview) + List simRoomBattleEventRecords, SimulationRoomBuffPreviewRecord randomBuffPreview, + int overclockSeason = 0, int battleEventGroup = 0, bool isOverclock = false) { var simRoomEvent = new NetSimRoomEvent(); var location = new NetSimRoomEventLocationInfo(); @@ -273,8 +306,17 @@ namespace EpinelPS.LobbyServer.Simroom location.Chapter = chapter.Chapter; location.Stage = stage; location.Order = order; - var simRoomBuffPreviewBattleEvents = simRoomBattleEventRecords.FindAll(x - => x.EventType == randomBuffPreview.EventType && x.DifficultyConditionValue <= chapter.DifficultyId); + var simRoomBuffPreviewBattleEvents = simRoomBattleEventRecords.FindAll(x => + x.EventType == randomBuffPreview.EventType + && x.DifficultyConditionValue <= chapter.DifficultyId + && x.UseOcMode == false); + if (isOverclock) + { + simRoomBuffPreviewBattleEvents = simRoomBattleEventRecords.FindAll(x => + x.EventType == randomBuffPreview.EventType + && x.UseOcMode == true && x.UseSeasonId == overclockSeason + && x.BattleEventGroup == battleEventGroup); + } log.Debug($"EventType: {randomBuffPreview.EventType}, SimRoomBattleEventRecord Count: {simRoomBuffPreviewBattleEvents.Count}"); var randomBattleEvents = GetRandomItems(simRoomBuffPreviewBattleEvents, 1); foreach (var battleEvent in randomBattleEvents) @@ -428,10 +470,42 @@ namespace EpinelPS.LobbyServer.Simroom } } + public static int GetBattleEventGroup(List? overclockOptionList = null, bool isOverclock = false) + { + // TODO: Implement battle event group logic + if (!isOverclock) return 0; + if (overclockOptionList is null || overclockOptionList.Count == 0) return 0; + var simRoomOcOptionRecords = GameData.Instance.SimulationRoomOcOptionTable.Values.Where(x => + overclockOptionList.Contains(x.Id)).ToList(); + if (simRoomOcOptionRecords is null || simRoomOcOptionRecords.Count == 0) return 0; + foreach (var item in simRoomOcOptionRecords.FindAll(x => x.OptionData.Count > 0)) + { + var optionData = item.OptionData.Find(x => x.OptionFunction == SimulationRoomOcOptionFunction.BattleEventGroupChange); + if (optionData is not null) return optionData.OptionValue; + } + return 0; + } + + public static bool GetIsHardBattle(List? overclockOptionList = null, bool isOverclock = false) + { + // TODO: Implement hard battle check logic + if (!isOverclock) return false; + if (overclockOptionList is null || overclockOptionList.Count == 0) return false; + var simRoomOcOptionRecords = GameData.Instance.SimulationRoomOcOptionTable.Values.Where(x => + overclockOptionList.Contains(x.Id)).ToList(); + if (simRoomOcOptionRecords is null || simRoomOcOptionRecords.Count == 0) return false; + foreach (var item in simRoomOcOptionRecords) + { + if (item.OptionNameLocalkey.EndsWith("_HARD_BATTLE_ONLY")) return true; + } + return false; + } + /// /// Update User SimRoomEvent Events /// - public static void UpdateUserSimRoomEvent(User user, int index, List events, int selectionNumber = 0, + public static void UpdateUserSimRoomEvent(User user, int index, List events, + int selectionNumber = 0, int selectionGroupElementId = 0, bool isDone = false, int battleProgress = 0, List? BuffOptions = null) { try @@ -441,7 +515,7 @@ namespace EpinelPS.LobbyServer.Simroom simRoomEvent.Selected = true; // Update Selection Group - var groupIndex = simRoomEvent.Selection.Group.FindIndex(x => x.SelectionNumber == selectionNumber); + var groupIndex = simRoomEvent.Selection.Group.FindIndex(x => x.Id == selectionGroupElementId || x.SelectionNumber == selectionNumber); if (groupIndex > -1 && isDone) { var group = simRoomEvent.Selection.Group[groupIndex]; @@ -472,104 +546,196 @@ namespace EpinelPS.LobbyServer.Simroom } } - public static List UpdateUserRemainingHps(User user, List? remainingHps = null, int teamNumber = 1, int HpValue = 10000) + public static List UpdateUserRemainingHps(User user, List? remainingHps = null, int teamNumber = 1, int hpValue = 10000) { - var userRemainingHps = user.ResetableData.SimRoomData.RemainingHps; try { - // req remainingHps - if (remainingHps is not null && remainingHps.Count > 0) + var userRemainingHps = user.ResetableData.SimRoomData.RemainingHps ?? []; + + // Update from input parameters + if (remainingHps?.Count > 0) { - foreach (var characterHp in remainingHps) - { - var userCharacterHpIndex = userRemainingHps.FindIndex(x => x.Csn == characterHp.Csn); - if (userCharacterHpIndex > -1) - { - userRemainingHps[userCharacterHpIndex] = new SimRoomCharacterHp { Csn = characterHp.Csn, Hp = characterHp.Hp }; - } - else - { - userRemainingHps.Add(new SimRoomCharacterHp { Csn = characterHp.Csn, Hp = characterHp.Hp }); - } - } + userRemainingHps = UpdateFromRemainingHps(userRemainingHps, remainingHps); } - // get user team - if (user.UserTeams.TryGetValue((int)TeamType.SimulationRoom, out var userTeam)) - { - var team = userTeam.Teams.FirstOrDefault(x => x.TeamNumber == teamNumber); - if (team is not null) - { - foreach (var slot in team.Slots) - { - if (userRemainingHps.FindIndex(x => x.Csn == slot.Value) < 0) userRemainingHps.Add(new SimRoomCharacterHp { Csn = slot.Value, Hp = HpValue }); - } - } - } - // update user + // Initialize team HPs + userRemainingHps = InitializeTeamHps(user, userRemainingHps, teamNumber, hpValue); + + // Save and return user.ResetableData.SimRoomData.RemainingHps = userRemainingHps; return userRemainingHps; } catch (Exception e) { log.Error($"Update UserRemainingHps Exception: {e.Message}"); + log.Error($"Stack Trace: {e.StackTrace}"); + return user.ResetableData.SimRoomData.RemainingHps ?? []; } - return userRemainingHps; } + private static List UpdateFromRemainingHps(List userRemainingHps, List remainingHps) + { + var existingHpsDict = userRemainingHps.ToDictionary(x => x.Csn, x => x); + foreach (var characterHp in remainingHps) + { + existingHpsDict[characterHp.Csn] = new SimRoomCharacterHp { Csn = characterHp.Csn, Hp = characterHp.Hp }; + } + + return [.. existingHpsDict.Values]; + } + + private static List InitializeTeamHps(User user, List userRemainingHps, int teamNumber, int hpValue) + { + if (!user.UserTeams.TryGetValue((int)TeamType.SimulationRoom, out var userTeam)) + return userRemainingHps; + + var team = userTeam.Teams.FirstOrDefault(x => x.TeamNumber == teamNumber); + if (team == null) + return userRemainingHps; + + var existingHpsDict = userRemainingHps.ToDictionary(x => x.Csn, x => x); + + foreach (var slot in team.Slots) + { + if (!existingHpsDict.ContainsKey(slot.Value)) + { + existingHpsDict[slot.Value] = new SimRoomCharacterHp { Csn = slot.Value, Hp = hpValue }; + } + } + + return [.. existingHpsDict.Values]; + } + + /// + /// Received Reward + /// + /// User + /// int difficultyId + /// int chapterId + /// NetRewardData public static NetRewardData? SimRoomReceivedReward(User user, int difficultyId, int chapterId) { // check if reward is received NetRewardData? reward = null; if (!IsRewardReceived(user, difficultyId, chapterId)) { + // get all chapter records for the current difficulty + var chapterRecords = GameData.Instance.SimulationRoomChapterTable.Values + .Where(x => x.DifficultyId <= difficultyId); - var allChapterRecords = GameData.Instance.SimulationRoomChapterTable.Values; - var chapter = allChapterRecords - .FirstOrDefault(x => x.DifficultyId == difficultyId && x.Chapter == chapterId); - - if (chapter is not null && chapter.RewardId > 0) + if (chapterRecords.Any()) { - var receivedRewardChapters = user.ResetableData.SimRoomData.ReceivedRewardChapters; + // get last received reward chapter + var receivedRewardChapters = user.ResetableData.SimRoomData.ReceivedRewardChapters ?? []; var receivedRewardChapter = receivedRewardChapters - .OrderBy(x => x.Difficulty) - .ThenBy(x => x.Chapter) - .LastOrDefault(); - SimulationRoomChapterRecord? receivedRewardChapterRecord = null; - if (receivedRewardChapter is not null) - { - receivedRewardChapterRecord = allChapterRecords - .FirstOrDefault(x => x.DifficultyId == receivedRewardChapter.Difficulty - && x.Chapter == receivedRewardChapter.Chapter); - } + .OrderBy(x => x.Difficulty).ThenBy(x => x.Chapter).LastOrDefault(); + + var receivedRewardChapterId = receivedRewardChapter?.Chapter ?? 0; + var receivedRewardDifficultyId = receivedRewardChapter?.Difficulty ?? 0; reward = new NetRewardData(); - if (receivedRewardChapterRecord is null) + + // + bool shouldAddRewardChapter = false; + List IncrementalRewards = []; + foreach (var chapter in chapterRecords) + { + bool shouldCalculateReward = chapter.DifficultyId > receivedRewardDifficultyId || + (chapter.DifficultyId == receivedRewardDifficultyId && chapter.Chapter > receivedRewardChapterId); + + if (shouldCalculateReward) + { + CalculateIncrementalReward(ref IncrementalRewards, chapter.RewardId); + } + + if (chapter.Chapter == chapterId && chapter.DifficultyId == difficultyId) + { + shouldAddRewardChapter = true; + } + } + + if (shouldAddRewardChapter) { - // Claiming the reward for the first time - reward = RewardUtils.RegisterRewardsForUser(user, rewardId: chapter.RewardId); AddRewardChapter(user, difficultyId, chapterId); } - // Check if the received reward chapter is lower than the current chapter - else if (receivedRewardChapterRecord.DifficultyId == difficultyId && receivedRewardChapterRecord.Chapter < chapter.Chapter) + foreach (var item in IncrementalRewards) { - // Claiming the reward for a higher chapter - reward = CalculateIncrementalReward(user, chapter, receivedRewardChapterRecord); - AddRewardChapter(user, difficultyId, chapterId); - } - // Check if the received reward chapter is lower than the current difficulty - else if (receivedRewardChapterRecord.DifficultyId < difficultyId) - { - // Claiming the reward for a higher difficulty - reward = RewardUtils.RegisterRewardsForUser(user, rewardId: chapter.RewardId); - AddRewardChapter(user, difficultyId, chapterId); + RewardUtils.AddSingleObject(user, ref reward, item.RewardId, item.RewardType, item.RewardValue); } } } return reward; } + /// + /// Overclock Received Reward + /// + /// User + /// NetRewardData + public static NetRewardData? SimRoomOverclockReceivedReward(User user) + { + // check if reward is received + NetRewardData? reward = null; + var currentSeasonData = user.ResetableData.SimRoomData.CurrentSeasonData; + if (currentSeasonData is null) return null; + if (!currentSeasonData.IsOverclock) return null; + + var currentOptionList = currentSeasonData.CurrentOptionList; + if (currentOptionList is null || currentOptionList.Count == 0) return null; + + var lastHighOption = currentSeasonData.CurrentSeasonHighScore; + var lastOptionLevel = lastHighOption?.OptionLevel ?? 0; + + var currentSeasonRecord = GameData.Instance.SimulationRoomOcSeasonTable.Values + .FirstOrDefault(x => x.Id == currentSeasonData.CurrentSeason); + if (currentSeasonRecord is null) return null; + + var currentOptionRecords = GameData.Instance.SimulationRoomOcOptionTable.Values + .Where(x => currentOptionList.Contains(x.Id)).ToList(); + + if (currentOptionRecords.Count == 0) return null; + var currentOptionLevel = currentOptionRecords.Max(x => x.OptionOverclockLevel); + + // Update User Latest Option + if (currentOptionLevel > 0) + { + user.ResetableData.SimRoomData.CurrentSeasonData.LatestOption = new OverclockHighScoreData() + { + Season = currentSeasonData.CurrentSeason, + OptionLevel = currentOptionLevel, + OptionList = currentOptionList + }; + } + + if (currentOptionLevel <= lastOptionLevel) return null; + if (currentSeasonRecord.OverclockLevelGroup <= 0) return null; + + // get all oc level records for the current season and option level + var ocLevelRecords = GameData.Instance.SimulationRoomOcLevelTable.Values + .Where(x => x.GroupId == currentSeasonRecord.OverclockLevelGroup + && x.OverclockLevel <= currentOptionLevel + && x.OverclockLevel > lastOptionLevel + && x.RewardId > 0).ToList(); + + if (ocLevelRecords == null || ocLevelRecords.Count == 0) return null; + + reward = new NetRewardData(); + + List IncrementalRewards = []; + + foreach (var ocLevel in ocLevelRecords) + { + CalculateIncrementalReward(ref IncrementalRewards, ocLevel.RewardId); + } + + foreach (var item in IncrementalRewards) + { + RewardUtils.AddSingleObject(user, ref reward, item.RewardId, item.RewardType, item.RewardValue); + } + return reward; + } + /// /// Check if reward is received /// @@ -580,6 +746,7 @@ namespace EpinelPS.LobbyServer.Simroom log.Debug($"IsRewardReceived (diff: {difficultyId}, chapter: {chapterId}): {isReceived}"); return isReceived; } + /// /// Add reward chapter /// @@ -595,39 +762,119 @@ namespace EpinelPS.LobbyServer.Simroom /// /// Calculate incremental reward /// - /// Incremental reward data - private static NetRewardData CalculateIncrementalReward(User user, - SimulationRoomChapterRecord chapter, SimulationRoomChapterRecord receivedChapterRecord) + private static void CalculateIncrementalReward(ref List IncrementalRewards, int rewardId) { - var reward = new NetRewardData(); - var rewardRecord = GameData.Instance.GetRewardTableEntry(chapter.RewardId); - var receivedRewardRecord = GameData.Instance.GetRewardTableEntry(receivedChapterRecord.RewardId); - - if (rewardRecord?.Rewards == null || receivedRewardRecord?.Rewards == null) + var rewardRecord = GameData.Instance.GetRewardTableEntry(rewardId); + if (rewardRecord is not null && rewardRecord.Rewards.Count > 0) { - // If rewardRecord or receivedRewardRecord is empty, return the complete reward record - reward = RewardUtils.RegisterRewardsForUser(user, rewardId: chapter.RewardId); - } - else - { - var receivedRewardIds = receivedRewardRecord.Rewards - .Where(x => x != null) - .ToDictionary(x => x.RewardId, x => x.RewardValue); - - foreach (var rewardItem in rewardRecord.Rewards.Where(x => x != null)) + foreach (var rewardItem in rewardRecord.Rewards.Where(x => x is not null && x.RewardValue > 0)) { - int receivedAmount = receivedRewardIds.GetValueOrDefault(rewardItem.RewardId, 0); - int remainingAmount = Math.Max(0, rewardItem.RewardValue - receivedAmount); - - if (remainingAmount > 0) + // If reward already exists, increment its value, otherwise add it to the list + var rewardIndex = IncrementalRewards.FindIndex(x => x.RewardId == rewardItem.RewardId); + if (rewardIndex > -1) { - RewardUtils.AddSingleObject(user, ref reward, rewardItem.RewardId, - rewardType: rewardItem.RewardType, remainingAmount); + IncrementalRewards[rewardIndex].RewardValue = IncrementalRewards[rewardIndex].RewardValue + rewardItem.RewardValue; + } + else + { + IncrementalRewards.Add(rewardItem); } } } - - return reward; } + + public static void UpdateOverclockHighScoreData(User user, NetSimRoomEventLocationInfo location) + { + var currentSeasonData = user.ResetableData.SimRoomData.CurrentSeasonData; + + // Check if current season is overclock, if not, quit + if (currentSeasonData is null || !currentSeasonData.IsOverclock) + { + return; + } + + var events = user.ResetableData.SimRoomData.Events; + var simRoomEventIndex = events.FindIndex(x => + x.Location.Chapter == location.Chapter && x.Location.Stage == location.Stage && x.Location.Order == location.Order); + if (simRoomEventIndex > -1) + { + var simRoomEvent = events[simRoomEventIndex]; + // TODO: This is a temporary solution, need to find a better way to determine if the challenge is completed + var maxStage = events.Max(e => e.Location.Stage); + if (simRoomEvent.Location.Stage == maxStage) + { + var currentOptionList = currentSeasonData.CurrentOptionList; + if (currentOptionList.Count <= 0) + { + // If currentOptionList is empty, quit + return; + } + var ocOptionTable = GameData.Instance.SimulationRoomOcOptionTable.Values.ToList(); + var currentOptions = ocOptionTable.Where(x => currentOptionList.Contains(x.Id)).ToList(); + int currentOptionLevel = currentOptions.Sum(x => x.OptionOverclockLevel); + + + + var highScoreData = CreateOrUpdateHighScoreData(currentSeasonData, currentOptionList, currentOptionLevel, ocOptionTable); + if (highScoreData is null) return; // If highScoreData is null, quit + + if (currentOptionLevel >= 50) + { + currentSeasonData.HasClearedLevel50 = true; + } + + // Update User CurrentSeasonData + highScoreData.CreatedAt = DateTime.UtcNow.Date.ToTimestamp(); + currentSeasonData.CurrentSeasonHighScore = highScoreData; + currentSeasonData.CurrentSubSeasonHighScore = highScoreData; + user.ResetableData.SimRoomData.CurrentSeasonData = currentSeasonData; + } + } + else + { + log.Warn($"Not Found User.ResetableData.SimRoomData.Events"); + } + + } + + private static OverclockHighScoreData? CreateOrUpdateHighScoreData( + OverclockData currentSeasonData, List currentOptionList, + int currentOptionLevel, List ocOptionTable) + { + + var currentHighOptionList = currentSeasonData.CurrentSeasonHighScore.OptionList; + + // If currentHighOptionList is empty, return new HighScoreData + if (currentHighOptionList.Count <= 0) + { + return new OverclockHighScoreData + { + Season = currentSeasonData.CurrentSeason, + SubSeason = currentSeasonData.CurrentSubSeason, + OptionList = currentOptionList, + OptionLevel = currentOptionLevel + }; + } + + // Get current high options, current high option level + var currentHighOptions = ocOptionTable.Where(x => currentHighOptionList.Contains(x.Id)); + int currentHighOptionLevel = currentHighOptions.Sum(x => x.OptionOverclockLevel); + + // If current option level is greater than current high option level, return new HighScoreData + if (currentOptionLevel >= currentHighOptionLevel) + { + return new OverclockHighScoreData + { + Season = currentSeasonData.CurrentSeason, + SubSeason = currentSeasonData.CurrentSubSeason, + OptionList = currentOptionList, + OptionLevel = currentOptionLevel + }; + } + + return null; + } + + } } \ No newline at end of file diff --git a/EpinelPS/LobbyServer/Team/SetTeam.cs b/EpinelPS/LobbyServer/Team/SetTeam.cs index 80a9354..9ea94a1 100644 --- a/EpinelPS/LobbyServer/Team/SetTeam.cs +++ b/EpinelPS/LobbyServer/Team/SetTeam.cs @@ -1,5 +1,4 @@ -using EpinelPS.Data; -using EpinelPS.Database; +using EpinelPS.Database; using EpinelPS.Utils; namespace EpinelPS.LobbyServer.Team @@ -21,9 +20,10 @@ namespace EpinelPS.LobbyServer.Team // Add team data to user data int contentsId = req.ContentsId + 1; // Default to 1 if not provided - if (req.Type == (int)TeamType.StoryEvent) + + if (req.Teams.Count != 0) { - contentsId = 1; // Default to 1 for story event teams + contentsId = req.Teams.Select(x => x.TeamNumber).Max(x => x); } NetUserTeamData teamData = new() { LastContentsTeamNumber = contentsId, Type = req.Type }; diff --git a/EpinelPS/Models/DbModels.cs b/EpinelPS/Models/DbModels.cs index 3b8a1af..d662f13 100644 --- a/EpinelPS/Models/DbModels.cs +++ b/EpinelPS/Models/DbModels.cs @@ -38,6 +38,7 @@ namespace EpinelPS.Models public int Skill1Lvl = 1; public int Skill2Lvl = 1; public int Grade = 0; + public bool IsMainForce = false; } public class MainQuestData { @@ -128,6 +129,29 @@ namespace EpinelPS.Models public List ReceivedRewardChapters = []; public bool IsSimpleModeSkipEnabled = false; public bool Entered = false; + public OverclockData CurrentSeasonData = new(); + } + public class OverclockData + { + public int CurrentSeason; + public int CurrentSubSeason; + public List CurrentOptionList = []; + public bool IsOverclock = false; + public bool HasClearedLevel50 = false; + public bool WasInfinitePopupChecked = false; + public bool WasMainSeasonResetPopupChecked = true; + public bool WasSubSeasonResetPopupChecked = true; + public OverclockHighScoreData CurrentSeasonHighScore = new(); + public OverclockHighScoreData CurrentSubSeasonHighScore = new(); + public OverclockHighScoreData LatestOption = new(); + } + public class OverclockHighScoreData + { + public int Season; + public int SubSeason; + public List OptionList = []; + public int OptionLevel; + public Google.Protobuf.WellKnownTypes.Timestamp? CreatedAt; } public class SimRoomEvent { diff --git a/EpinelPS/Models/UserModel.cs b/EpinelPS/Models/UserModel.cs index b6335db..9919b6a 100644 --- a/EpinelPS/Models/UserModel.cs +++ b/EpinelPS/Models/UserModel.cs @@ -460,7 +460,10 @@ public class User { SimRoomData = new() { - LegacyBuffs = ResetableData.SimRoomData.LegacyBuffs // Retain old LegacyBuffs data + LegacyBuffs = ResetableData.SimRoomData.LegacyBuffs, // Retain old LegacyBuffs data + CurrentDifficulty = ResetableData.SimRoomData.CurrentDifficulty, + CurrentChapter = ResetableData.SimRoomData.CurrentChapter, + CurrentSeasonData = ResetableData.SimRoomData.CurrentSeasonData, } }; needsSave = true; @@ -472,7 +475,18 @@ public class User Logging.WriteLine("Resetting weekly user data...", LogType.Warning); LastWeeklyReset = DateTime.UtcNow; - ResetableData = new(); + var currentSeasonData = ResetableData.SimRoomData.CurrentSeasonData; + currentSeasonData.LatestOption = new(); + ResetableData = new() + { + SimRoomData = new() + { + // Retain old LegacyBuffs data and currentSeason data + CurrentDifficulty = ResetableData.SimRoomData.CurrentDifficulty, + CurrentChapter = ResetableData.SimRoomData.CurrentChapter, + CurrentSeasonData = currentSeasonData, + } + }; needsSave = true; }