mirror of
https://github.com/EpinelPS/EpinelPS.git
synced 2025-12-12 15:04:36 +01:00
feat: Implement SimRoom Overclock-实现模拟室超频 (#68)
- Added GetAcquireBuffFunction to handle buff acquisition requests in the simulation room. - Added InfinitePopupCheck to manage infinite popup checks for users. - Added ProceedSkipFunction to process skip requests in the simulation room. - Updated SelectDifficulty to handle overclock options and season data. - Enhanced SimRoomHelper to support overclock mechanics and event group logic. - Modified GetSimRoomData to include buffs and legacy buffs in the response. - Updated Quit functionality to reset overclock state upon quitting the simulation room. - Added logic to handle overclock rewards and high score updates. - Refactored user model to retain current season data and legacy buffs during resets. - Introduced new OverclockData and OverclockHighScoreData models to manage overclock states.
This commit is contained in:
@@ -26,3 +26,6 @@ dotnet_diagnostic.SYSLIB0039.severity = none
|
|||||||
|
|
||||||
# CS0219: 变量已被赋值,但从未使用过它的值
|
# CS0219: 变量已被赋值,但从未使用过它的值
|
||||||
dotnet_diagnostic.CS0219.severity = none
|
dotnet_diagnostic.CS0219.severity = none
|
||||||
|
|
||||||
|
# CS8618: 类型不包含 null 值的属性
|
||||||
|
dotnet_diagnostic.CS8618.severity = none
|
||||||
@@ -309,6 +309,16 @@ namespace EpinelPS.Data
|
|||||||
[LoadRecord("SimulationRoomBuffTable.json", "Id")]
|
[LoadRecord("SimulationRoomBuffTable.json", "Id")]
|
||||||
public readonly Dictionary<int, SimulationRoomBuffRecord> SimulationRoomBuffTable = [];
|
public readonly Dictionary<int, SimulationRoomBuffRecord> SimulationRoomBuffTable = [];
|
||||||
|
|
||||||
|
// SimulationRoom Overclock Data Tables
|
||||||
|
[LoadRecord("SimulationRoomOcLevelTable.json", "Id")]
|
||||||
|
public readonly Dictionary<int, SimulationRoomOverclockLevelRecord> SimulationRoomOcLevelTable = [];
|
||||||
|
[LoadRecord("SimulationRoomOcOptionGroupTable.json", "Id")]
|
||||||
|
public readonly Dictionary<int, SimulationRoomOverclockOptionGroupRecord> SimulationRoomOcOptionGroupTable = [];
|
||||||
|
[LoadRecord("SimulationRoomOcOptionTable.json", "Id")]
|
||||||
|
public readonly Dictionary<int, SimulationRoomOverclockOptionRecord> SimulationRoomOcOptionTable = [];
|
||||||
|
[LoadRecord("SimulationRoomOcSeasonTable.json", "Id")]
|
||||||
|
public readonly Dictionary<int, SimulationRoomOverclockSeasonRecord> SimulationRoomOcSeasonTable = [];
|
||||||
|
|
||||||
static async Task<GameData> BuildAsync()
|
static async Task<GameData> BuildAsync()
|
||||||
{
|
{
|
||||||
await Load();
|
await Load();
|
||||||
@@ -350,8 +360,9 @@ namespace EpinelPS.Data
|
|||||||
{
|
{
|
||||||
using FileStream fileStream = File.Open(file, FileMode.Open, FileAccess.Read);
|
using FileStream fileStream = File.Open(file, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
Rfc2898DeriveBytes a = new(PresharedValue, data.GetSalt2Bytes(), 10000, HashAlgorithmName.SHA256);
|
// Rfc2898DeriveBytes a = new(PresharedValue, data.GetSalt2Bytes(), 10000, HashAlgorithmName.SHA256);
|
||||||
byte[] key2 = a.GetBytes(32);
|
// byte[] key2 = a.GetBytes(32);
|
||||||
|
byte[] key2 = Rfc2898DeriveBytes.Pbkdf2(PresharedValue, data.GetSalt2Bytes(), 10000, HashAlgorithmName.SHA256, 32);
|
||||||
|
|
||||||
byte[] decryptionKey = key2[0..16];
|
byte[] decryptionKey = key2[0..16];
|
||||||
byte[] iv = key2[16..32];
|
byte[] iv = key2[16..32];
|
||||||
@@ -387,8 +398,9 @@ namespace EpinelPS.Data
|
|||||||
throw new Exception("error 3");
|
throw new Exception("error 3");
|
||||||
|
|
||||||
dataMs.Position = 0;
|
dataMs.Position = 0;
|
||||||
Rfc2898DeriveBytes keyDec2 = new(PresharedValue, data.GetSalt1Bytes(), 10000, HashAlgorithmName.SHA256);
|
// Rfc2898DeriveBytes keyDec2 = new(PresharedValue, data.GetSalt1Bytes(), 10000, HashAlgorithmName.SHA256);
|
||||||
byte[] key3 = keyDec2.GetBytes(32);
|
// byte[] key3 = keyDec2.GetBytes(32);
|
||||||
|
byte[] key3 = Rfc2898DeriveBytes.Pbkdf2(PresharedValue, data.GetSalt1Bytes(), 10000, HashAlgorithmName.SHA256, 32);
|
||||||
|
|
||||||
byte[] val2 = key3[0..16];
|
byte[] val2 = key3[0..16];
|
||||||
byte[] iv2 = key3[16..32];
|
byte[] iv2 = key3[16..32];
|
||||||
|
|||||||
@@ -13,7 +13,27 @@ namespace EpinelPS.LobbyServer.Character
|
|||||||
ResGetCharacterData response = new();
|
ResGetCharacterData response = new();
|
||||||
foreach (CharacterModel item in user.Characters)
|
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<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
|
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
|
||||||
|
|||||||
29
EpinelPS/LobbyServer/Character/SetCharacterMainForce.cs
Normal file
29
EpinelPS/LobbyServer/Character/SetCharacterMainForce.cs
Normal file
@@ -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<ReqSetCharacterMainForce>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ namespace EpinelPS.LobbyServer.ContentsOpen
|
|||||||
JsonDb.Save();
|
JsonDb.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (KeyValuePair<int, UnlockData> item in user.ContentsOpenUnlocked)
|
foreach (KeyValuePair<int, UnlockData> item in user.ContentsOpenUnlocked.OrderBy(x => x.Key))
|
||||||
{
|
{
|
||||||
response.ContentsOpenUnlockInfoList.Add(new NetContentsOpenUnlockInfo()
|
response.ContentsOpenUnlockInfoList.Add(new NetContentsOpenUnlockInfo()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using EpinelPS.Utils;
|
using EpinelPS.Data;
|
||||||
|
using EpinelPS.Utils;
|
||||||
|
|
||||||
namespace EpinelPS.LobbyServer.LobbyUser
|
namespace EpinelPS.LobbyServer.LobbyUser
|
||||||
{
|
{
|
||||||
@@ -7,12 +8,12 @@ namespace EpinelPS.LobbyServer.LobbyUser
|
|||||||
{
|
{
|
||||||
protected override async Task HandleAsync()
|
protected override async Task HandleAsync()
|
||||||
{
|
{
|
||||||
ReqGetContentsOpenData req = await ReadData<ReqGetContentsOpenData>();
|
await ReadData<ReqGetContentsOpenData>();
|
||||||
User user = GetUser();
|
User user = GetUser();
|
||||||
|
|
||||||
// this request returns a list of "special" stages that mark when something is unlocked, ex: the shop or interception
|
// this request returns a list of "special" stages that mark when something is unlocked, ex: the shop or interception
|
||||||
|
|
||||||
List<int> 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<int> 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();
|
ResGetContentsOpenData response = new();
|
||||||
foreach (FieldInfoNew field in user.FieldInfoNew.Values)
|
foreach (FieldInfoNew field in user.FieldInfoNew.Values)
|
||||||
@@ -23,12 +24,40 @@ namespace EpinelPS.LobbyServer.LobbyUser
|
|||||||
response.ClearStageList.Add(stage);
|
response.ClearStageList.Add(stage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response.MaxGachaCount = 10;
|
response.MaxGachaCount = user.GachaTutorialPlayCount;
|
||||||
response.MaxGachaPremiumCount = 10;
|
response.MaxGachaPremiumCount = user.GachaTutorialPlayCount;
|
||||||
// todo tutorial playcount of gacha
|
// todo tutorial playcount of gacha
|
||||||
response.TutorialGachaPlayCount = user.GachaTutorialPlayCount;
|
response.TutorialGachaPlayCount = user.GachaTutorialPlayCount;
|
||||||
|
|
||||||
|
// ClearSimRoomChapterList: 已通关的章节列表,用于显示超频选项 SimRoomOC
|
||||||
|
response.ClearSimRoomChapterList.AddRange(GetClearSimRoomChapterList(user));
|
||||||
|
|
||||||
await WriteDataAsync(response);
|
await WriteDataAsync(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<int> GetClearSimRoomChapterList(User user)
|
||||||
|
{
|
||||||
|
var clearSimRoomChapterList = new List<int>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,16 @@ namespace EpinelPS.LobbyServer.LobbyUser
|
|||||||
{
|
{
|
||||||
protected override async Task HandleAsync()
|
protected override async Task HandleAsync()
|
||||||
{
|
{
|
||||||
ReqGetUserTitleCounterList req = await ReadData<ReqGetUserTitleCounterList>();
|
await ReadData<ReqGetUserTitleCounterList>();
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
EpinelPS/LobbyServer/Simroom/GetAcquireBuffFunction.cs
Normal file
44
EpinelPS/LobbyServer/Simroom/GetAcquireBuffFunction.cs
Normal file
@@ -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<ReqGetSimRoomAcquireBuffFunction>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,8 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
|
|
||||||
var CurrentDifficulty = user.ResetableData.SimRoomData.CurrentDifficulty;
|
var CurrentDifficulty = user.ResetableData.SimRoomData.CurrentDifficulty;
|
||||||
var currentChapter = user.ResetableData.SimRoomData.CurrentChapter;
|
var currentChapter = user.ResetableData.SimRoomData.CurrentChapter;
|
||||||
|
var buffs = user.ResetableData.SimRoomData.Buffs;
|
||||||
|
var legacyBuffs = user.ResetableData.SimRoomData.LegacyBuffs;
|
||||||
|
|
||||||
ResGetSimRoom response = new()
|
ResGetSimRoom response = new()
|
||||||
{
|
{
|
||||||
@@ -41,20 +43,34 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
// NextLegacyBuffResetDate: Resets at 2 AM every Tuesday
|
// NextLegacyBuffResetDate: Resets at 2 AM every Tuesday
|
||||||
NextLegacyBuffResetDate = DateTimeHelper.GetNextWeekdayAtTime("China Standard Time", DayOfWeek.Tuesday, 2).ToTimestamp(),
|
NextLegacyBuffResetDate = DateTimeHelper.GetNextWeekdayAtTime("China Standard Time", DayOfWeek.Tuesday, 2).ToTimestamp(),
|
||||||
IsSimpleModeSkipEnabled = user.ResetableData.SimRoomData.IsSimpleModeSkipEnabled,
|
IsSimpleModeSkipEnabled = user.ResetableData.SimRoomData.IsSimpleModeSkipEnabled,
|
||||||
|
LastPlayedChapter = new NetSimRoomChapterInfo()
|
||||||
|
{
|
||||||
|
Chapter = currentChapter,
|
||||||
|
Difficulty = CurrentDifficulty,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// LegacyBuffs
|
// LegacyBuffs
|
||||||
response.LegacyBuffs.AddRange(user.ResetableData.SimRoomData.LegacyBuffs);
|
response.LegacyBuffs.AddRange(legacyBuffs);
|
||||||
|
|
||||||
// OverclockData
|
// 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
|
// ClearInfos
|
||||||
response.ClearInfos.AddRange(GetClearInfos(user));
|
response.ClearInfos.AddRange(GetClearInfos(user));
|
||||||
|
|
||||||
// OverclockOptionList
|
// 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
|
// check if user is in sim room
|
||||||
if (user.ResetableData.SimRoomData.Entered)
|
if (user.ResetableData.SimRoomData.Entered)
|
||||||
@@ -65,15 +81,9 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
// TODO: Get RemainingHps
|
// TODO: Get RemainingHps
|
||||||
response.RemainingHps.AddRange(GetCharacterHp(user));
|
response.RemainingHps.AddRange(GetCharacterHp(user));
|
||||||
|
|
||||||
response.LastPlayedChapter = new NetSimRoomChapterInfo()
|
|
||||||
{
|
|
||||||
Chapter = currentChapter,
|
|
||||||
Difficulty = CurrentDifficulty,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Buffs = Buffs + LegacyBuffs
|
// Buffs = Buffs + LegacyBuffs
|
||||||
response.Buffs.AddRange(user.ResetableData.SimRoomData.Buffs);
|
response.Buffs.AddRange(buffs);
|
||||||
response.Buffs.AddRange(user.ResetableData.SimRoomData.LegacyBuffs);
|
response.Buffs.AddRange(legacyBuffs);
|
||||||
|
|
||||||
// response.NextSimpleModeBuffSelectionInfo = new()
|
// response.NextSimpleModeBuffSelectionInfo = new()
|
||||||
// {
|
// {
|
||||||
@@ -144,57 +154,66 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
public static List<NetSimRoomCharacterHp> GetCharacterHp(User user)
|
public static List<NetSimRoomCharacterHp> GetCharacterHp(User user)
|
||||||
{
|
{
|
||||||
List<NetSimRoomCharacterHp> hps = [];
|
List<NetSimRoomCharacterHp> 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)
|
hps.Add(new() { Csn = userRemainingHp.Csn, Hp = userRemainingHp.Hp });
|
||||||
{
|
|
||||||
foreach (var slot in userTeamData.Teams[0].Slots)
|
|
||||||
{
|
|
||||||
hps.Add(new() { Csn = slot.Value, Hp = 100000 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return hps;
|
return hps;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NetSimRoomOverclockData GetOverclockData(User user)
|
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
|
CurrentSeasonData = new NetSimRoomOverclockSeasonData
|
||||||
{
|
{
|
||||||
SeasonStartDate = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(-1)),
|
SeasonStartDate = DateTime.UtcNow.Date.AddDays(-2).ToTimestamp(),
|
||||||
SeasonEndDate = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(7)),
|
SeasonEndDate = DateTime.UtcNow.Date.AddDays(12).ToTimestamp(),
|
||||||
IsSeasonOpen = true,
|
IsSeasonOpen = true,
|
||||||
Season = 1,
|
Season = currentSeasonData.CurrentSeason,
|
||||||
SubSeason = 1,
|
SubSeason = currentSeasonData.CurrentSubSeason,
|
||||||
SeasonWeekCount = 1
|
SeasonWeekCount = 2,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// CurrentSeasonHighScore
|
||||||
CurrentSeasonHighScore = new NetSimRoomOverclockHighScoreData
|
CurrentSeasonHighScore = new NetSimRoomOverclockHighScoreData
|
||||||
{
|
{
|
||||||
CreatedAt = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(-1)),
|
CreatedAt = currentSeasonData.CurrentSeasonHighScore.CreatedAt ?? DateTime.UtcNow.Date.AddDays(-2).ToTimestamp(),
|
||||||
OptionLevel = 1,
|
Season = currentSeasonData.CurrentSeasonHighScore.Season,
|
||||||
Season = 1,
|
SubSeason = currentSeasonData.CurrentSeasonHighScore.SubSeason,
|
||||||
SubSeason = 1,
|
OptionList = { currentSeasonData.CurrentSeasonHighScore.OptionList },
|
||||||
OptionList = { 1 }
|
OptionLevel = currentSeasonData.CurrentSeasonHighScore.OptionLevel,
|
||||||
},
|
},
|
||||||
|
// CurrentSubSeasonHighScore
|
||||||
CurrentSubSeasonHighScore = new NetSimRoomOverclockHighScoreData
|
CurrentSubSeasonHighScore = new NetSimRoomOverclockHighScoreData
|
||||||
{
|
{
|
||||||
CreatedAt = Timestamp.FromDateTimeOffset(DateTime.UtcNow.Date.AddDays(-1)),
|
CreatedAt = currentSeasonData.CurrentSubSeasonHighScore.CreatedAt ?? DateTime.UtcNow.Date.AddDays(-2).ToTimestamp(),
|
||||||
OptionLevel = 1,
|
Season = currentSeasonData.CurrentSubSeasonHighScore.Season,
|
||||||
Season = 1,
|
SubSeason = currentSeasonData.CurrentSubSeasonHighScore.SubSeason,
|
||||||
SubSeason = 1,
|
OptionList = { currentSeasonData.CurrentSubSeasonHighScore.OptionList },
|
||||||
OptionList = { 1 }
|
OptionLevel = currentSeasonData.CurrentSubSeasonHighScore.OptionLevel,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// LatestOption
|
||||||
LatestOption = new NetSimRoomOverclockOptionSettingData
|
LatestOption = new NetSimRoomOverclockOptionSettingData
|
||||||
{
|
{
|
||||||
Season = 1,
|
Season = currentSeasonData.LatestOption.Season,
|
||||||
OptionList = { 1 }
|
OptionList = { currentSeasonData.LatestOption.OptionList },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
netOverclockData.CurrentSeasonData.Season = GameData.Instance.SimulationRoomOcSeasonTable.Keys.Max();
|
||||||
|
netOverclockData.CurrentSeasonData.SubSeason = 3;
|
||||||
|
|
||||||
|
return netOverclockData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
EpinelPS/LobbyServer/Simroom/InfinitePopupCheck.cs
Normal file
22
EpinelPS/LobbyServer/Simroom/InfinitePopupCheck.cs
Normal file
@@ -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<ReqInfinitePopupCheck>();
|
||||||
|
var user = GetUser();
|
||||||
|
|
||||||
|
ResInfinitePopupCheck response = new();
|
||||||
|
|
||||||
|
user.ResetableData.SimRoomData.CurrentSeasonData.WasInfinitePopupChecked = true;
|
||||||
|
JsonDb.Save();
|
||||||
|
|
||||||
|
await WriteDataAsync(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
EpinelPS/LobbyServer/Simroom/ProceedSkipFunction.cs
Normal file
40
EpinelPS/LobbyServer/Simroom/ProceedSkipFunction.cs
Normal file
@@ -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>();
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
user.ResetableData.SimRoomData.Events = [];
|
user.ResetableData.SimRoomData.Events = [];
|
||||||
user.ResetableData.SimRoomData.RemainingHps = [];
|
user.ResetableData.SimRoomData.RemainingHps = [];
|
||||||
user.ResetableData.SimRoomData.Buffs = [];
|
user.ResetableData.SimRoomData.Buffs = [];
|
||||||
|
user.ResetableData.SimRoomData.CurrentSeasonData.IsOverclock = false;
|
||||||
|
|
||||||
JsonDb.Save();
|
JsonDb.Save();
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
var difficulty = user.ResetableData.SimRoomData.CurrentDifficulty;
|
var difficulty = user.ResetableData.SimRoomData.CurrentDifficulty;
|
||||||
var reward = SimRoomHelper.SimRoomReceivedReward(user, difficulty, location.Chapter);
|
var reward = SimRoomHelper.SimRoomReceivedReward(user, difficulty, location.Chapter);
|
||||||
if (reward is not null) response.Reward = reward;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,22 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
user.ResetableData.SimRoomData.Entered = true;
|
user.ResetableData.SimRoomData.Entered = true;
|
||||||
user.ResetableData.SimRoomData.CurrentDifficulty = req.Difficulty;
|
user.ResetableData.SimRoomData.CurrentDifficulty = req.Difficulty;
|
||||||
user.ResetableData.SimRoomData.CurrentChapter = req.StartingChapter;
|
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();
|
JsonDb.Save();
|
||||||
|
|
||||||
List<NetSimRoomEvent> events = SimRoomHelper.GetSimRoomEvents(user);
|
List<NetSimRoomEvent> events = SimRoomHelper.GetSimRoomEvents(user, req.Difficulty, req.StartingChapter,
|
||||||
|
[.. req.OverclockOptionList], req.OverclockSeason, req.OverclockSubSeason);
|
||||||
|
|
||||||
user.ResetableData.SimRoomData.Events = [.. events.Select(SimRoomHelper.NetToM)];
|
user.ResetableData.SimRoomData.Events = [.. events.Select(SimRoomHelper.NetToM)];
|
||||||
JsonDb.Save();
|
JsonDb.Save();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using EpinelPS.Data;
|
using EpinelPS.Data;
|
||||||
using EpinelPS.Database;
|
using EpinelPS.Database;
|
||||||
using EpinelPS.Utils;
|
using EpinelPS.Utils;
|
||||||
|
using Google.Protobuf.WellKnownTypes;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
@@ -17,15 +18,32 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
/// <param name="user"> User </param>
|
/// <param name="user"> User </param>
|
||||||
/// <param name="difficultyId"> DifficultyId </param>
|
/// <param name="difficultyId"> DifficultyId </param>
|
||||||
/// <param name="chapterId"> ChapterId </param>
|
/// <param name="chapterId"> ChapterId </param>
|
||||||
|
/// <param name="overclockOptionList"> OverclockOptionList </param>
|
||||||
|
/// <param name="overclockSeason"> OverclockSeason </param>
|
||||||
|
/// <param name="overclockSubSeason"> OverclockSubSeason </param>
|
||||||
/// <returns>The list of NetSimRoomEvent</returns>
|
/// <returns>The list of NetSimRoomEvent</returns>
|
||||||
public static List<NetSimRoomEvent> GetSimRoomEvents(User user, int difficultyId = 0, int chapterId = 0)
|
public static List<NetSimRoomEvent> GetSimRoomEvents(User user, int difficultyId = 0, int chapterId = 0,
|
||||||
|
List<int>? overclockOptionList = null, int overclockSeason = 0, int overclockSubSeason = 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
bool isOverclock = overclockOptionList is not null && overclockOptionList.Count > 0 && overclockSeason > 0 && overclockSubSeason > 0;
|
||||||
|
|
||||||
List<NetSimRoomEvent> netSimRooms = [];
|
List<NetSimRoomEvent> netSimRooms = [];
|
||||||
|
var currentOCData = user.ResetableData.SimRoomData.CurrentSeasonData;
|
||||||
int currentDifficulty = user.ResetableData.SimRoomData.CurrentDifficulty;
|
int currentDifficulty = user.ResetableData.SimRoomData.CurrentDifficulty;
|
||||||
int currentChapter = user.ResetableData.SimRoomData.CurrentChapter;
|
int currentChapter = user.ResetableData.SimRoomData.CurrentChapter;
|
||||||
|
int currentOCSeason = currentOCData.CurrentSeason;
|
||||||
|
int currentOCSubSeason = currentOCData.CurrentSubSeason;
|
||||||
|
List<int> currentOCList = currentOCData.CurrentOptionList;
|
||||||
|
|
||||||
if (difficultyId > 0) currentDifficulty = difficultyId;
|
if (difficultyId > 0) currentDifficulty = difficultyId;
|
||||||
if (chapterId > 0) currentChapter = chapterId;
|
if (chapterId > 0) currentChapter = chapterId;
|
||||||
|
if (isOverclock)
|
||||||
|
{
|
||||||
|
currentOCSeason = overclockSeason;
|
||||||
|
currentOCSubSeason = overclockSubSeason;
|
||||||
|
currentOCList = overclockOptionList ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
var events = user.ResetableData.SimRoomData.Events;
|
var events = user.ResetableData.SimRoomData.Events;
|
||||||
if (events.Count > 1)
|
if (events.Count > 1)
|
||||||
@@ -33,7 +51,8 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
return [.. events.Select(MToNet)];
|
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)}");
|
log.Debug($"Fond SimulationRoomChapter Chapter: {currentChapter}, DifficultyId: {currentDifficulty} Data: {JsonConvert.SerializeObject(simRoomChapter)}");
|
||||||
|
|
||||||
var buffPreviewRecords = GameData.Instance.SimulationRoomBuffPreviewTable.Values.ToList();
|
var buffPreviewRecords = GameData.Instance.SimulationRoomBuffPreviewTable.Values.ToList();
|
||||||
@@ -43,13 +62,18 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
|
|
||||||
if (simRoomChapter is null) return netSimRooms;
|
if (simRoomChapter is null) return netSimRooms;
|
||||||
|
|
||||||
|
int battleEventGroup = GetBattleEventGroup(overclockOptionList, isOverclock);
|
||||||
|
bool isHardBattle = GetIsHardBattle(overclockOptionList, isOverclock);
|
||||||
|
|
||||||
for (int i = 1; i <= simRoomChapter.StageValue; i++)
|
for (int i = 1; i <= simRoomChapter.StageValue; i++)
|
||||||
{
|
{
|
||||||
if (i == simRoomChapter.StageValue) // BossBattle
|
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 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));
|
events.Add(NetToM(simRoomBattleEvent));
|
||||||
netSimRooms.Add(simRoomBattleEvent);
|
netSimRooms.Add(simRoomBattleEvent);
|
||||||
}
|
}
|
||||||
@@ -117,18 +141,26 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
{
|
{
|
||||||
var battleBuffPreviews = buffPreviewRecords.FindAll(x
|
var battleBuffPreviews = buffPreviewRecords.FindAll(x
|
||||||
=> x.EventType is SimulationRoomEvent.NormalBattle or SimulationRoomEvent.EliteBattle);
|
=> 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);
|
var randomBuffPreview = GetRandomItems(battleBuffPreviews, 3);
|
||||||
int order = 0;
|
int order = 0;
|
||||||
foreach (var simRoomBuffPreview in randomBuffPreview)
|
foreach (var simRoomBuffPreview in randomBuffPreview)
|
||||||
{
|
{
|
||||||
order += 1;
|
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));
|
events.Add(NetToM(simRoomBattleEvent));
|
||||||
netSimRooms.Add(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;
|
user.ResetableData.SimRoomData.Events = events;
|
||||||
JsonDb.Save();
|
JsonDb.Save();
|
||||||
return netSimRooms;
|
return netSimRooms;
|
||||||
@@ -264,7 +296,8 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
/// <param name="randomBuffPreview"></param>
|
/// <param name="randomBuffPreview"></param>
|
||||||
/// <returns>NetSimRoomEvent</returns>
|
/// <returns>NetSimRoomEvent</returns>
|
||||||
private static NetSimRoomEvent CreateSimRoomBattleEvent(SimulationRoomChapterRecord chapter, int stage, int order,
|
private static NetSimRoomEvent CreateSimRoomBattleEvent(SimulationRoomChapterRecord chapter, int stage, int order,
|
||||||
List<SimulationRoomBattleEventRecord> simRoomBattleEventRecords, SimulationRoomBuffPreviewRecord randomBuffPreview)
|
List<SimulationRoomBattleEventRecord> simRoomBattleEventRecords, SimulationRoomBuffPreviewRecord randomBuffPreview,
|
||||||
|
int overclockSeason = 0, int battleEventGroup = 0, bool isOverclock = false)
|
||||||
{
|
{
|
||||||
var simRoomEvent = new NetSimRoomEvent();
|
var simRoomEvent = new NetSimRoomEvent();
|
||||||
var location = new NetSimRoomEventLocationInfo();
|
var location = new NetSimRoomEventLocationInfo();
|
||||||
@@ -273,8 +306,17 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
location.Chapter = chapter.Chapter;
|
location.Chapter = chapter.Chapter;
|
||||||
location.Stage = stage;
|
location.Stage = stage;
|
||||||
location.Order = order;
|
location.Order = order;
|
||||||
var simRoomBuffPreviewBattleEvents = simRoomBattleEventRecords.FindAll(x
|
var simRoomBuffPreviewBattleEvents = simRoomBattleEventRecords.FindAll(x =>
|
||||||
=> x.EventType == randomBuffPreview.EventType && x.DifficultyConditionValue <= chapter.DifficultyId);
|
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}");
|
log.Debug($"EventType: {randomBuffPreview.EventType}, SimRoomBattleEventRecord Count: {simRoomBuffPreviewBattleEvents.Count}");
|
||||||
var randomBattleEvents = GetRandomItems(simRoomBuffPreviewBattleEvents, 1);
|
var randomBattleEvents = GetRandomItems(simRoomBuffPreviewBattleEvents, 1);
|
||||||
foreach (var battleEvent in randomBattleEvents)
|
foreach (var battleEvent in randomBattleEvents)
|
||||||
@@ -428,10 +470,42 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetBattleEventGroup(List<int>? 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<int>? 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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update User SimRoomEvent Events
|
/// Update User SimRoomEvent Events
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void UpdateUserSimRoomEvent(User user, int index, List<SimRoomEvent> events, int selectionNumber = 0,
|
public static void UpdateUserSimRoomEvent(User user, int index, List<SimRoomEvent> events,
|
||||||
|
int selectionNumber = 0, int selectionGroupElementId = 0,
|
||||||
bool isDone = false, int battleProgress = 0, List<int>? BuffOptions = null)
|
bool isDone = false, int battleProgress = 0, List<int>? BuffOptions = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -441,7 +515,7 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
simRoomEvent.Selected = true;
|
simRoomEvent.Selected = true;
|
||||||
|
|
||||||
// Update Selection Group
|
// 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)
|
if (groupIndex > -1 && isDone)
|
||||||
{
|
{
|
||||||
var group = simRoomEvent.Selection.Group[groupIndex];
|
var group = simRoomEvent.Selection.Group[groupIndex];
|
||||||
@@ -472,104 +546,196 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SimRoomCharacterHp> UpdateUserRemainingHps(User user, List<NetSimRoomCharacterHp>? remainingHps = null, int teamNumber = 1, int HpValue = 10000)
|
public static List<SimRoomCharacterHp> UpdateUserRemainingHps(User user, List<NetSimRoomCharacterHp>? remainingHps = null, int teamNumber = 1, int hpValue = 10000)
|
||||||
{
|
{
|
||||||
var userRemainingHps = user.ResetableData.SimRoomData.RemainingHps;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// req remainingHps
|
var userRemainingHps = user.ResetableData.SimRoomData.RemainingHps ?? [];
|
||||||
if (remainingHps is not null && remainingHps.Count > 0)
|
|
||||||
|
// Update from input parameters
|
||||||
|
if (remainingHps?.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var characterHp in remainingHps)
|
userRemainingHps = UpdateFromRemainingHps(userRemainingHps, 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 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get user team
|
// Initialize team HPs
|
||||||
if (user.UserTeams.TryGetValue((int)TeamType.SimulationRoom, out var userTeam))
|
userRemainingHps = InitializeTeamHps(user, userRemainingHps, teamNumber, hpValue);
|
||||||
{
|
|
||||||
var team = userTeam.Teams.FirstOrDefault(x => x.TeamNumber == teamNumber);
|
// Save and return
|
||||||
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
|
|
||||||
user.ResetableData.SimRoomData.RemainingHps = userRemainingHps;
|
user.ResetableData.SimRoomData.RemainingHps = userRemainingHps;
|
||||||
return userRemainingHps;
|
return userRemainingHps;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
log.Error($"Update UserRemainingHps Exception: {e.Message}");
|
log.Error($"Update UserRemainingHps Exception: {e.Message}");
|
||||||
|
log.Error($"Stack Trace: {e.StackTrace}");
|
||||||
|
return user.ResetableData.SimRoomData.RemainingHps ?? [];
|
||||||
}
|
}
|
||||||
return userRemainingHps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<SimRoomCharacterHp> UpdateFromRemainingHps(List<SimRoomCharacterHp> userRemainingHps, List<NetSimRoomCharacterHp> 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<SimRoomCharacterHp> InitializeTeamHps(User user, List<SimRoomCharacterHp> 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Received Reward
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">User</param>
|
||||||
|
/// <param name="difficultyId">int difficultyId</param>
|
||||||
|
/// <param name="chapterId">int chapterId</param>
|
||||||
|
/// <returns>NetRewardData</returns>
|
||||||
public static NetRewardData? SimRoomReceivedReward(User user, int difficultyId, int chapterId)
|
public static NetRewardData? SimRoomReceivedReward(User user, int difficultyId, int chapterId)
|
||||||
{
|
{
|
||||||
// check if reward is received
|
// check if reward is received
|
||||||
NetRewardData? reward = null;
|
NetRewardData? reward = null;
|
||||||
if (!IsRewardReceived(user, difficultyId, chapterId))
|
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;
|
if (chapterRecords.Any())
|
||||||
var chapter = allChapterRecords
|
|
||||||
.FirstOrDefault(x => x.DifficultyId == difficultyId && x.Chapter == chapterId);
|
|
||||||
|
|
||||||
if (chapter is not null && chapter.RewardId > 0)
|
|
||||||
{
|
{
|
||||||
var receivedRewardChapters = user.ResetableData.SimRoomData.ReceivedRewardChapters;
|
// get last received reward chapter
|
||||||
|
var receivedRewardChapters = user.ResetableData.SimRoomData.ReceivedRewardChapters ?? [];
|
||||||
var receivedRewardChapter = receivedRewardChapters
|
var receivedRewardChapter = receivedRewardChapters
|
||||||
.OrderBy(x => x.Difficulty)
|
.OrderBy(x => x.Difficulty).ThenBy(x => x.Chapter).LastOrDefault();
|
||||||
.ThenBy(x => x.Chapter)
|
|
||||||
.LastOrDefault();
|
var receivedRewardChapterId = receivedRewardChapter?.Chapter ?? 0;
|
||||||
SimulationRoomChapterRecord? receivedRewardChapterRecord = null;
|
var receivedRewardDifficultyId = receivedRewardChapter?.Difficulty ?? 0;
|
||||||
if (receivedRewardChapter is not null)
|
|
||||||
{
|
|
||||||
receivedRewardChapterRecord = allChapterRecords
|
|
||||||
.FirstOrDefault(x => x.DifficultyId == receivedRewardChapter.Difficulty
|
|
||||||
&& x.Chapter == receivedRewardChapter.Chapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
reward = new NetRewardData();
|
reward = new NetRewardData();
|
||||||
if (receivedRewardChapterRecord is null)
|
|
||||||
|
//
|
||||||
|
bool shouldAddRewardChapter = false;
|
||||||
|
List<Reward_Data> 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);
|
AddRewardChapter(user, difficultyId, chapterId);
|
||||||
}
|
}
|
||||||
// Check if the received reward chapter is lower than the current chapter
|
foreach (var item in IncrementalRewards)
|
||||||
else if (receivedRewardChapterRecord.DifficultyId == difficultyId && receivedRewardChapterRecord.Chapter < chapter.Chapter)
|
|
||||||
{
|
{
|
||||||
// Claiming the reward for a higher chapter
|
RewardUtils.AddSingleObject(user, ref reward, item.RewardId, item.RewardType, item.RewardValue);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return reward;
|
return reward;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overclock Received Reward
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">User</param>
|
||||||
|
/// <returns>NetRewardData</returns>
|
||||||
|
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<Reward_Data> 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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if reward is received
|
/// Check if reward is received
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -580,6 +746,7 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
log.Debug($"IsRewardReceived (diff: {difficultyId}, chapter: {chapterId}): {isReceived}");
|
log.Debug($"IsRewardReceived (diff: {difficultyId}, chapter: {chapterId}): {isReceived}");
|
||||||
return isReceived;
|
return isReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add reward chapter
|
/// Add reward chapter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -595,39 +762,119 @@ namespace EpinelPS.LobbyServer.Simroom
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate incremental reward
|
/// Calculate incremental reward
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Incremental reward data</returns>
|
private static void CalculateIncrementalReward(ref List<Reward_Data> IncrementalRewards, int rewardId)
|
||||||
private static NetRewardData CalculateIncrementalReward(User user,
|
|
||||||
SimulationRoomChapterRecord chapter, SimulationRoomChapterRecord receivedChapterRecord)
|
|
||||||
{
|
{
|
||||||
var reward = new NetRewardData();
|
var rewardRecord = GameData.Instance.GetRewardTableEntry(rewardId);
|
||||||
var rewardRecord = GameData.Instance.GetRewardTableEntry(chapter.RewardId);
|
if (rewardRecord is not null && rewardRecord.Rewards.Count > 0)
|
||||||
var receivedRewardRecord = GameData.Instance.GetRewardTableEntry(receivedChapterRecord.RewardId);
|
|
||||||
|
|
||||||
if (rewardRecord?.Rewards == null || receivedRewardRecord?.Rewards == null)
|
|
||||||
{
|
{
|
||||||
// If rewardRecord or receivedRewardRecord is empty, return the complete reward record
|
foreach (var rewardItem in rewardRecord.Rewards.Where(x => x is not null && x.RewardValue > 0))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
int receivedAmount = receivedRewardIds.GetValueOrDefault(rewardItem.RewardId, 0);
|
// If reward already exists, increment its value, otherwise add it to the list
|
||||||
int remainingAmount = Math.Max(0, rewardItem.RewardValue - receivedAmount);
|
var rewardIndex = IncrementalRewards.FindIndex(x => x.RewardId == rewardItem.RewardId);
|
||||||
|
if (rewardIndex > -1)
|
||||||
if (remainingAmount > 0)
|
|
||||||
{
|
{
|
||||||
RewardUtils.AddSingleObject(user, ref reward, rewardItem.RewardId,
|
IncrementalRewards[rewardIndex].RewardValue = IncrementalRewards[rewardIndex].RewardValue + rewardItem.RewardValue;
|
||||||
rewardType: rewardItem.RewardType, remainingAmount);
|
}
|
||||||
|
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<int> currentOptionList,
|
||||||
|
int currentOptionLevel, List<SimulationRoomOverclockOptionRecord> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using EpinelPS.Data;
|
using EpinelPS.Database;
|
||||||
using EpinelPS.Database;
|
|
||||||
using EpinelPS.Utils;
|
using EpinelPS.Utils;
|
||||||
|
|
||||||
namespace EpinelPS.LobbyServer.Team
|
namespace EpinelPS.LobbyServer.Team
|
||||||
@@ -21,9 +20,10 @@ namespace EpinelPS.LobbyServer.Team
|
|||||||
|
|
||||||
// Add team data to user data
|
// Add team data to user data
|
||||||
int contentsId = req.ContentsId + 1; // Default to 1 if not provided
|
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 };
|
NetUserTeamData teamData = new() { LastContentsTeamNumber = contentsId, Type = req.Type };
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace EpinelPS.Models
|
|||||||
public int Skill1Lvl = 1;
|
public int Skill1Lvl = 1;
|
||||||
public int Skill2Lvl = 1;
|
public int Skill2Lvl = 1;
|
||||||
public int Grade = 0;
|
public int Grade = 0;
|
||||||
|
public bool IsMainForce = false;
|
||||||
}
|
}
|
||||||
public class MainQuestData
|
public class MainQuestData
|
||||||
{
|
{
|
||||||
@@ -128,6 +129,29 @@ namespace EpinelPS.Models
|
|||||||
public List<SimRoomChapterInfo> ReceivedRewardChapters = [];
|
public List<SimRoomChapterInfo> ReceivedRewardChapters = [];
|
||||||
public bool IsSimpleModeSkipEnabled = false;
|
public bool IsSimpleModeSkipEnabled = false;
|
||||||
public bool Entered = false;
|
public bool Entered = false;
|
||||||
|
public OverclockData CurrentSeasonData = new();
|
||||||
|
}
|
||||||
|
public class OverclockData
|
||||||
|
{
|
||||||
|
public int CurrentSeason;
|
||||||
|
public int CurrentSubSeason;
|
||||||
|
public List<int> 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<int> OptionList = [];
|
||||||
|
public int OptionLevel;
|
||||||
|
public Google.Protobuf.WellKnownTypes.Timestamp? CreatedAt;
|
||||||
}
|
}
|
||||||
public class SimRoomEvent
|
public class SimRoomEvent
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -460,7 +460,10 @@ public class User
|
|||||||
{
|
{
|
||||||
SimRoomData = new()
|
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;
|
needsSave = true;
|
||||||
@@ -472,7 +475,18 @@ public class User
|
|||||||
Logging.WriteLine("Resetting weekly user data...", LogType.Warning);
|
Logging.WriteLine("Resetting weekly user data...", LogType.Warning);
|
||||||
|
|
||||||
LastWeeklyReset = DateTime.UtcNow;
|
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;
|
needsSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user