From de1b4081b2ab18f0c255dcbdd8d8b2491f8e9ffa Mon Sep 17 00:00:00 2001 From: User958568 Date: Mon, 22 Sep 2025 03:02:56 +0300 Subject: [PATCH] InTheMirror Arcade's game (#56) --- EpinelPS/Data/GameData.cs | 11 ++ EpinelPS/Data/JsonStaticData.cs | 124 +++++++++++++++++- .../InTheMirror/GetAcquireMvgCollectable.cs | 22 ++++ .../InTheMirror/GetBuyFromArcadeMvgShop.cs | 15 +++ .../Minigame/InTheMirror/GetMvgData.cs | 18 +++ .../Minigame/InTheMirror/GetMvgInteraction.cs | 16 +++ .../Minigame/InTheMirror/GetMvgLogModule.cs | 15 +++ .../InTheMirror/GetMvgLogModuleLimit.cs | 15 +++ .../Minigame/InTheMirror/GetMvgLogState.cs | 16 +++ .../Minigame/InTheMirror/GetMvgLogUnlock.cs | 16 +++ .../Minigame/InTheMirror/GetMvgLogUpgrade.cs | 15 +++ .../Minigame/InTheMirror/GetMvgSave.cs | 22 ++++ .../GetObtainAchievementMissionReward.cs | 38 ++++++ .../InTheMirror/GetObtainMvgQuestReward.cs | 34 +++++ .../InTheMirror/GetStartMvgNewGame.cs | 26 ++++ .../InTheMirror/GetStartMvgNewGamePlus.cs | 54 ++++++++ EpinelPS/Models/UserModel.cs | 1 + EpinelPS/Utils/NetUtils.cs | 5 + 18 files changed, 462 insertions(+), 1 deletion(-) create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetAcquireMvgCollectable.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetBuyFromArcadeMvgShop.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgData.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgInteraction.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModule.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModuleLimit.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogState.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUnlock.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUpgrade.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgSave.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainAchievementMissionReward.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainMvgQuestReward.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGame.cs create mode 100644 EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGamePlus.cs diff --git a/EpinelPS/Data/GameData.cs b/EpinelPS/Data/GameData.cs index 0cd6ced..ae8c050 100644 --- a/EpinelPS/Data/GameData.cs +++ b/EpinelPS/Data/GameData.cs @@ -243,6 +243,17 @@ namespace EpinelPS.Data [LoadRecord("EventPlaySodaPointRewardTable.json", "id")] public readonly Dictionary EventPlaySodaPointRewardTable = []; + // Tables related to InTheMirror Arcade's event. + + [LoadRecord("EventMvgQuestTable.json", "id")] + public readonly Dictionary EventMvgQuestTable = []; + + [LoadRecord("EventMvgQuestTable.json", "id")] + public readonly Dictionary EventMvgShopTable = []; + + [LoadRecord("EventMVGMissionTable.json", "id")] + public readonly Dictionary EventMvgMissionTable = []; + static async Task BuildAsync() { await Load(); diff --git a/EpinelPS/Data/JsonStaticData.cs b/EpinelPS/Data/JsonStaticData.cs index 0c55a93..7d4af54 100644 --- a/EpinelPS/Data/JsonStaticData.cs +++ b/EpinelPS/Data/JsonStaticData.cs @@ -1,5 +1,6 @@ -using System.Data; using MemoryPack; +using System.Data; +using System.Runtime.Serialization; namespace EpinelPS.Data { @@ -1174,5 +1175,126 @@ namespace EpinelPS.Data public EventPlaySodaGameType game_type; public int step; public int reward_id; + } + + [MemoryPackable] + public partial class EventMVGQuestRecord_Raw + { + public int id; + public int condition_id; + public int next_quest_id; + public int parents_quest_id; + public int time_line_group_id; + public int reward_id; + public EventMVGQuestConditionType condition_type; + public int condition_value_1; + public string condition_value_2 = ""; + public string description_localkey = ""; + public string name_localkey = ""; + public MVGQuestTargetType quest_target_type; + public MVGQuestType quest_type; + } + + public enum EventMVGQuestConditionType + { + StartMission, + EndMission, + KillMonster, + MissionTargetPoint, + ClearMultiCondition, + GetCollectable, + GetCurrency, + PlatformSwitchInteraction, + ConditionCheckSwitchInteraction, + TeleportDeviceInteraction + } + + public enum MVGQuestTargetType + { + First, + Loop + } + + public enum MVGQuestType + { + Normal, + MotherMission, + ChildMission + } + + [MemoryPackable] + public partial class EventMVGShopRecord_Raw + { + public int id; + public int group_id; + public int itemId; + public string desc = ""; + public int itemSlot; + public EventMVGShopItemTypeData itemType; + public EventMVGQuestConditionType condition_type; + public int order; + //public List< condition_value_2 = ""; + public string description_localkey = ""; + public string name_localkey = ""; + public MVGQuestTargetType quest_target_type; + public MVGQuestType quest_type; + } + + public enum EventMVGShopItemTypeData + { + Collectable, + Module, + None + } + + [MemoryPackable] + public partial class EventMVGMissionRecord_Raw + { + public int id; + public int mvg_id; + public int condition_id; + public int condition_value; + public int order; + public string name_localkey = ""; + public EventMVGMissionType mission_type; + public EventMVGMIssionSubType mission_sub_type; + public EventMVGMissionConditionType condition_type; + public bool display_type; + public bool is_reset; + public int reward_id; + public int point_value; + } + + public enum EventMVGMissionType + { + Daily, + Achievement + } + + public enum EventMVGMIssionSubType + { + None, + MonsterKill, + BossMonsterKill, + GetItem, + ChapterClear, + Explorer + } + + public enum EventMVGMissionConditionType + { + KillMonster, + KillBossMonster, + GetCurrency, + GetCollectable, + None, + ClearAchievement, + TargetPoint, + ClearMap, + GetUpgradeMax, + GetModule, + UseKey, + GetMemory, + PlayMVG, } } diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetAcquireMvgCollectable.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetAcquireMvgCollectable.cs new file mode 100644 index 0000000..e7b45aa --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetAcquireMvgCollectable.cs @@ -0,0 +1,22 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/collectable")] + public class GetAcquireMvgCollectable : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + var request = await ReadData(); + + var user = GetUser(); + + user.ArcadeInTheMirrorData.Collectables.Add(request.CollectableId); + + await WriteDataAsync(new ResAcquireArcadeMvgCollectable()); + + JsonDb.Save(); + } + } +} \ No newline at end of file diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetBuyFromArcadeMvgShop.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetBuyFromArcadeMvgShop.cs new file mode 100644 index 0000000..5647130 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetBuyFromArcadeMvgShop.cs @@ -0,0 +1,15 @@ +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/shop")] + public class GetBuyFromArcadeMvgShop : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + await WriteDataAsync(new ResBuyFromArcadeMvgShop()); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgData.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgData.cs new file mode 100644 index 0000000..1c18077 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgData.cs @@ -0,0 +1,18 @@ +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/get")] + public class GetMvgData : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + var user = GetUser(); + + await WriteDataAsync(new ResGetArcadeMvgData() { Data = user.ArcadeInTheMirrorData }); + + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgInteraction.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgInteraction.cs new file mode 100644 index 0000000..ff4eff4 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgInteraction.cs @@ -0,0 +1,16 @@ +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/interaction")] + public class GetMvgLogInteraction : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + await WriteDataAsync(new ResLogArcadeMvgInteraction()); + + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModule.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModule.cs new file mode 100644 index 0000000..b9448ab --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModule.cs @@ -0,0 +1,15 @@ +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/module")] + public class GetMvgLogModule : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + await WriteDataAsync(new ResEquipArcadeMvgModule()); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModuleLimit.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModuleLimit.cs new file mode 100644 index 0000000..c3ef1d9 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogModuleLimit.cs @@ -0,0 +1,15 @@ +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/module/limit")] + public class GetMvgLogModuleLimit : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + await WriteDataAsync(new ResIncreaseArcadeMvgModuleLimit()); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogState.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogState.cs new file mode 100644 index 0000000..c4f98ae --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogState.cs @@ -0,0 +1,16 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/state")] + public class GetMvgLogState : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + await WriteDataAsync(new ResLogArcadeMvgState()); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUnlock.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUnlock.cs new file mode 100644 index 0000000..c98c98c --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUnlock.cs @@ -0,0 +1,16 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/unlock")] + public class GetMvgLogUpdate : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + await WriteDataAsync(new ResUnlockArcadeMvg()); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUpgrade.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUpgrade.cs new file mode 100644 index 0000000..6c20572 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgLogUpgrade.cs @@ -0,0 +1,15 @@ +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/log/upgrade")] + public class GetMvgLogUpgrade : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + await WriteDataAsync(new ResBuyFromArcadeMvgUpgradeShop() ); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgSave.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgSave.cs new file mode 100644 index 0000000..aacdb91 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetMvgSave.cs @@ -0,0 +1,22 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/save")] + public class GetMvgSave : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + var request = await ReadData(); + + var user = GetUser(); + + user.ArcadeInTheMirrorData = request.Data; + + await WriteDataAsync(new ResSaveArcadeMvgData()); + + JsonDb.Save(); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainAchievementMissionReward.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainAchievementMissionReward.cs new file mode 100644 index 0000000..5717021 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainAchievementMissionReward.cs @@ -0,0 +1,38 @@ +using EpinelPS.Data; +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.PlaySoda +{ + [PacketPath("/arcade/mvg/obtainachievementmissionreward")] + public class ReqObtainAchievementMissionReward : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + var request = await ReadData(); + + var user = GetUser(); + + List rewards = []; + + foreach (var missionId in request.MissionIds) + { + var mission = GameData.Instance.EventMvgMissionTable[missionId]; + user.ArcadeInTheMirrorData.AchievementMissions.First(m => m.MissionId == mission.id).IsReceived = true; + + var achievement_mission = GameData.Instance.EventMvgMissionTable.First(m => m.Key > mission.id && m.Value.condition_type == EventMVGMissionConditionType.ClearAchievement); + user.ArcadeInTheMirrorData.AchievementMissions.First(m => m.MissionId == achievement_mission.Key).Progress++; + + rewards.Add(RewardUtils.RegisterRewardsForUser(user, mission.reward_id)); + } + + var response = new ResObtainArcadeMvgAchievementMissionReward() { Reward = NetUtils.MergeRewards(rewards, user) }; + response.Missions.AddRange(user.ArcadeInTheMirrorData.AchievementMissions); + + await WriteDataAsync(response); + + JsonDb.Save(); + } + + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainMvgQuestReward.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainMvgQuestReward.cs new file mode 100644 index 0000000..6dfab9a --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetObtainMvgQuestReward.cs @@ -0,0 +1,34 @@ +using EpinelPS.Data; +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/obtainquestreward")] + public class GetObtainMvgQuestReward : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + var request = await ReadData(); + + var user = GetUser(); + + List rewards = []; + + foreach (var questId in request.QuestIds) + { + var quest = GameData.Instance.EventMvgQuestTable[questId]; + if (quest.id != 0) + { + user.ArcadeInTheMirrorData.Quests.First(q => q.QuestId == quest.id).IsReceived = true; + + rewards.Add(RewardUtils.RegisterRewardsForUser(user, quest.reward_id)); + } + } + + await WriteDataAsync(new ResObtainArcadeMvgQuestReward() { Reward = NetUtils.MergeRewards(rewards, user) }); + + JsonDb.Save(); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGame.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGame.cs new file mode 100644 index 0000000..c4ff69a --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGame.cs @@ -0,0 +1,26 @@ +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/newgame")] + public class GetStartMvgNewGame : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + await ReadData(); + + var user = GetUser(); + + user.ArcadeInTheMirrorData.Gold = 0; + user.ArcadeInTheMirrorData.Core = 0; + user.ArcadeInTheMirrorData.Quests.Clear(); + user.ArcadeInTheMirrorData.Collectables.Clear(); + user.ArcadeInTheMirrorData.ProgressJson = ""; + + await WriteDataAsync(new ResStartArcadeMvgNewGame()); + + JsonDb.Save(); + } + } +} diff --git a/EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGamePlus.cs b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGamePlus.cs new file mode 100644 index 0000000..aa8c388 --- /dev/null +++ b/EpinelPS/LobbyServer/Minigame/InTheMirror/GetStartMvgNewGamePlus.cs @@ -0,0 +1,54 @@ +using EpinelPS.Data; +using EpinelPS.Database; +using EpinelPS.Utils; + +namespace EpinelPS.LobbyServer.Minigame.InTheMirror +{ + [PacketPath("/arcade/mvg/newgameplus")] + public class GetStartMvgNewGamePlus : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + var request = await ReadData(); + + var user = GetUser(); + + foreach (var questData in user.ArcadeInTheMirrorData.Quests.Where(q => q.IsReceived == false)) + { + var quest = GameData.Instance.EventMvgQuestTable[questData.QuestId]; + if (quest.reward_id != 0) + { + foreach (var rewardEntry in GameData.Instance.RewardDataRecords[quest.reward_id].rewards ??= []) + { + if (!string.IsNullOrEmpty(rewardEntry.reward_type)) + { + switch (rewardEntry.reward_id) + { + case 9810003: + user.ArcadeInTheMirrorData.Gold += rewardEntry.reward_value; + break; + case 9811001: + user.ArcadeInTheMirrorData.Core += rewardEntry.reward_value; + break; + default: + break; + } + } + } + } + } + + foreach (var quest in user.ArcadeInTheMirrorData.Quests) + { + quest.Progress = default; + quest.IsReceived = default; + } + + user.ArcadeInTheMirrorData.ProgressJson = request.ProgressJson; + + await WriteDataAsync(new ResStartArcadeMvgNewGamePlus()); + + JsonDb.Save(); + } + } +} diff --git a/EpinelPS/Models/UserModel.cs b/EpinelPS/Models/UserModel.cs index ca1a6ab..061cade 100644 --- a/EpinelPS/Models/UserModel.cs +++ b/EpinelPS/Models/UserModel.cs @@ -103,6 +103,7 @@ public class User public Dictionary EventInfo = []; public MogMinigameInfo MogInfo = new(); public List ArcadePlaySodaInfoList = []; + public NetArcadeMvgData ArcadeInTheMirrorData = new(); public TriggerModel AddTrigger(TriggerType type, int value, int conditionId = 0) { diff --git a/EpinelPS/Utils/NetUtils.cs b/EpinelPS/Utils/NetUtils.cs index 810ac63..81fa16b 100644 --- a/EpinelPS/Utils/NetUtils.cs +++ b/EpinelPS/Utils/NetUtils.cs @@ -162,6 +162,11 @@ namespace EpinelPS.Utils foreach (NetPointData? item in reward.Point) { result.Point.Add(item); + } + + foreach (int item in reward.JukeboxBgm) + { + result.JukeboxBgm.Add(item); } foreach (NetCharacterData? c in reward.Character)