diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..426ca62 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# CA5397: Do not use deprecated SslProtocols values +dotnet_diagnostic.CA5397.severity = none diff --git a/EpinelPS.Analyzers/LoadRecordInitializerGenerator.cs b/EpinelPS.Analyzers/LoadRecordInitializerGenerator.cs index ff96d37..85ef9f9 100644 --- a/EpinelPS.Analyzers/LoadRecordInitializerGenerator.cs +++ b/EpinelPS.Analyzers/LoadRecordInitializerGenerator.cs @@ -42,12 +42,15 @@ public class LoadRecordInitializerGenerator : IIncrementalGenerator if (context.SemanticModel.GetDeclaredSymbol(variable) is not IFieldSymbol symbol) return null; + if (symbol.Type is not INamedTypeSymbol namedSymbol) + return null; + foreach (var attr in symbol.GetAttributes()) { - if (attr.ConstructorArguments.Length == 3) + if (attr.ConstructorArguments.Length == 2) { - if (attr.ConstructorArguments[0].Value is not string fileName || attr.ConstructorArguments[1].Value is not string key || attr.ConstructorArguments[2].Value is not INamedTypeSymbol recordType) + if (attr.ConstructorArguments[0].Value is not string fileName || attr.ConstructorArguments[1].Value is not string key) return null; return new LoadFieldInfo @@ -56,7 +59,7 @@ public class LoadRecordInitializerGenerator : IIncrementalGenerator FieldName = symbol.Name, FileName = fileName, Key = key, - RecordTypeName = recordType.ToDisplayString() + RecordTypeName = namedSymbol.TypeArguments[1].Name }; } } @@ -71,23 +74,24 @@ public class LoadRecordInitializerGenerator : IIncrementalGenerator sb.AppendLine("using System.Threading.Tasks;"); sb.AppendLine(); sb.AppendLine("namespace EpinelPS.Data;"); + sb.AppendLine(); sb.AppendLine("public static class GameDataInitializer"); sb.AppendLine("{"); - sb.AppendFormat($"public static int TotalFiles = {fieldInfos.Length};"); - sb.AppendLine(" public static async Task InitializeGameData(IProgress progress = null)"); - sb.AppendLine(" {"); + sb.AppendLine($"\tpublic static int TotalFiles = {fieldInfos.Length};"); + sb.AppendLine("\tpublic static async Task InitializeGameData(IProgress progress = null)"); + sb.AppendLine("\t{"); foreach (var info in fieldInfos) { var tempVar = $"data_{info.FieldName}"; - sb.AppendLine($" var {tempVar} = await {info.ContainingClass}.Instance.LoadZip<{info.RecordTypeName}>(\"{info.FileName}\", progress);"); - sb.AppendLine($" foreach (var obj in {tempVar}.records)"); - sb.AppendLine(" {"); - sb.AppendLine($" {info.ContainingClass}.Instance.{info.FieldName}.Add(obj.{info.Key}, obj);"); - sb.AppendLine(" }"); + sb.AppendLine($"\t\tvar {tempVar} = await {info.ContainingClass}.Instance.LoadZip<{info.RecordTypeName}>(\"{info.FileName}\", progress);"); + sb.AppendLine($"\t\tforeach (var obj in {tempVar})"); + sb.AppendLine("\t\t{"); + sb.AppendLine($"\t\t\t{info.ContainingClass}.Instance.{info.FieldName}.Add(obj.{info.Key}, obj);"); + sb.AppendLine("\t\t}"); } - sb.AppendLine(" }"); + sb.AppendLine("\t}"); sb.AppendLine("}"); return sb.ToString(); diff --git a/EpinelPS.sln b/EpinelPS.sln index b0c1d05..c7b0510 100644 --- a/EpinelPS.sln +++ b/EpinelPS.sln @@ -13,6 +13,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{4BB2E7 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpinelPS.Analyzers", "EpinelPS.Analyzers\EpinelPS.Analyzers.csproj", "{E3B18A3D-B20B-447D-BCBE-12931E18B41E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/EpinelPS/Data/GameData.cs b/EpinelPS/Data/GameData.cs index 8a5bda4..682431e 100644 --- a/EpinelPS/Data/GameData.cs +++ b/EpinelPS/Data/GameData.cs @@ -1,9 +1,11 @@ -using EpinelPS.Utils; -using ICSharpCode.SharpZipLib.Zip; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Data; using System.Diagnostics; using System.Security.Cryptography; +using EpinelPS.Utils; +using ICSharpCode.SharpZipLib.Zip; +using MemoryPack; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace EpinelPS.Data { @@ -33,171 +35,175 @@ namespace EpinelPS.Data private int totalFiles = 1; private int currentFile = 0; + // TODO: all of the data types need to be changed to match the game + private bool UseMemoryPack = false; + public readonly Dictionary MapData = []; - [LoadRecord("MainQuestTable.json", "id", typeof(MainQuestCompletionTable))] + [LoadRecord("MainQuestTable.json", "id")] public readonly Dictionary QuestDataRecords = []; - [LoadRecord("CampaignStageTable.json", "id", typeof(CampaignStageTable))] + [LoadRecord("CampaignStageTable.json", "id")] public readonly Dictionary StageDataRecords = []; - [LoadRecord("RewardTable.json", "id", typeof(RewardTable))] + [LoadRecord("RewardTable.json", "id")] public readonly Dictionary RewardDataRecords = []; - [LoadRecord("UserExpTable.json", "level", typeof(UserExpTable))] + [LoadRecord("UserExpTable.json", "level")] public readonly Dictionary UserExpDataRecords = []; - [LoadRecord("CampaignChapterTable.json", "chapter", typeof(CampaignChapterTable))] + [LoadRecord("CampaignChapterTable.json", "chapter")] public readonly Dictionary ChapterCampaignData = []; - [LoadRecord("CharacterCostumeTable.json", "id", typeof(CharacterCostumeTable))] + [LoadRecord("CharacterCostumeTable.json", "id")] public readonly Dictionary CharacterCostumeTable = []; - [LoadRecord("CharacterTable.json", "id", typeof(CharacterTable))] + [LoadRecord("CharacterTable.json", "id")] public readonly Dictionary CharacterTable = []; - [LoadRecord("ContentsTutorialTable.json", "id", typeof(TutorialTable))] + [LoadRecord("ContentsTutorialTable.json", "id")] public readonly Dictionary TutorialTable = []; - [LoadRecord("ItemEquipTable.json", "id", typeof(ItemEquipTable))] + [LoadRecord("ItemEquipTable.json", "id")] public readonly Dictionary ItemEquipTable = []; - [LoadRecord("ItemMaterialTable.json", "id", typeof(ItemMaterialTable))] + [LoadRecord("ItemMaterialTable.json", "id")] public readonly Dictionary itemMaterialTable = []; - [LoadRecord("ItemEquipExpTable.json", "id", typeof(ItemEquipExpTable))] + [LoadRecord("ItemEquipExpTable.json", "id")] public readonly Dictionary itemEquipExpTable = []; - [LoadRecord("ItemEquipGradeExpTable.json", "id", typeof(ItemEquipGradeExpTable))] + [LoadRecord("ItemEquipGradeExpTable.json", "id")] public readonly Dictionary ItemEquipGradeExpTable = []; - [LoadRecord("CharacterLevelTable.json", "level", typeof(CharacterLevelTable))] + [LoadRecord("CharacterLevelTable.json", "level")] public readonly Dictionary LevelData = []; - [LoadRecord("TacticAcademyFunctionTable.json", "id", typeof(TacticAcademyLessonTable))] + [LoadRecord("TacticAcademyFunctionTable.json", "id")] public readonly Dictionary TacticAcademyLessons = []; - [LoadRecord("SideStoryStageTable.json", "id", typeof(SideStoryStageTable))] + [LoadRecord("SideStoryStageTable.json", "id")] public readonly Dictionary SidestoryRewardTable = []; - [LoadRecord("FieldItemTable.json", "id", typeof(FieldItemTable))] + [LoadRecord("FieldItemTable.json", "id")] public readonly Dictionary FieldItems = []; - [LoadRecord("OutpostBattleTable.json", "id", typeof(OutpostBattleTable))] + [LoadRecord("OutpostBattleTable.json", "id")] public readonly Dictionary OutpostBattle = []; - [LoadRecord("JukeboxListTable.json", "id", typeof(JukeboxListTable))] + [LoadRecord("JukeboxListTable.json", "id")] public readonly Dictionary jukeboxListDataRecords = []; - [LoadRecord("JukeboxThemeTable.json", "id", typeof(JukeboxThemeTable))] + [LoadRecord("JukeboxThemeTable.json", "id")] public readonly Dictionary jukeboxThemeDataRecords = []; - [LoadRecord("GachaTypeTable.json", "id", typeof(GachaTypeTable))] + [LoadRecord("GachaTypeTable.json", "id")] public readonly Dictionary gachaTypes = []; - [LoadRecord("EventManagerTable.json", "id", typeof(EventManagerTable))] + [LoadRecord("EventManagerTable.json", "id")] public readonly Dictionary eventManagers = []; - [LoadRecord("LiveWallpaperTable.json", "id", typeof(LiveWallpaperTable))] + [LoadRecord("LiveWallpaperTable.json", "id")] public readonly Dictionary lwptablemgrs = []; - [LoadRecord("AlbumResourceTable.json", "id", typeof(AlbumResourceTable))] + [LoadRecord("AlbumResourceTable.json", "id")] public readonly Dictionary albumResourceRecords = []; - [LoadRecord("UserFrameTable.json", "id", typeof(UserFrameTable))] + [LoadRecord("UserFrameTable.json", "id")] public readonly Dictionary userFrameTable = []; - [LoadRecord("ArchiveRecordManagerTable.json", "id", typeof(ArchiveRecordManagerTable))] + [LoadRecord("ArchiveRecordManagerTable.json", "id")] public readonly Dictionary archiveRecordManagerTable = []; - [LoadRecord("ArchiveEventStoryTable.json", "id", typeof(ArchiveEventStoryTable))] + [LoadRecord("ArchiveEventStoryTable.json", "id")] public readonly Dictionary archiveEventStoryRecords = []; - [LoadRecord("ArchiveEventQuestTable.json", "id", typeof(ArchiveEventQuestTable))] + [LoadRecord("ArchiveEventQuestTable.json", "id")] public readonly Dictionary archiveEventQuestRecords = []; - [LoadRecord("ArchiveEventDungeonStageTable.json", "id", typeof(ArchiveEventDungeonStageTable))] + [LoadRecord("ArchiveEventDungeonStageTable.json", "id")] public readonly Dictionary archiveEventDungeonStageRecords = []; - [LoadRecord("UserTitleTable.json", "id", typeof(UserTitleTable))] + [LoadRecord("UserTitleTable.json", "id")] public readonly Dictionary userTitleRecords = []; - [LoadRecord("ArchiveMessengerConditionTable.json", "id", typeof(ArchiveMessengerConditionTable))] + [LoadRecord("ArchiveMessengerConditionTable.json", "id")] public readonly Dictionary archiveMessengerConditionRecords = []; - [LoadRecord("CharacterStatTable.json", "id", typeof(CharacterStatTable))] + [LoadRecord("CharacterStatTable.json", "id")] public readonly Dictionary characterStatTable = []; - [LoadRecord("SkillInfoTable.json", "id", typeof(SkillInfoTable))] + [LoadRecord("SkillInfoTable.json", "id")] public readonly Dictionary skillInfoTable = []; - [LoadRecord("CostTable.json", "id", typeof(CostTable))] + [LoadRecord("CostTable.json", "id")] public readonly Dictionary costTable = []; - [LoadRecord("MidasProductTable.json", "midas_product_id_proximabeta", typeof(MidasProductTable))] + [LoadRecord("MidasProductTable.json", "midas_product_id_proximabeta")] public readonly Dictionary mediasProductTable = []; - [LoadRecord("TowerTable.json", "id", typeof(TowerTable))] + [LoadRecord("TowerTable.json", "id")] public readonly Dictionary towerTable = []; - [LoadRecord("TriggerTable.json", "id", typeof(TriggerTable))] + [LoadRecord("TriggerTable.json", "id")] public readonly Dictionary TriggerTable = []; - [LoadRecord("InfraCoreGradeTable.json", "id", typeof(InfracoreTable))] + [LoadRecord("InfraCoreGradeTable.json", "id")] public readonly Dictionary InfracoreTable = []; - [LoadRecord("AttractiveCounselCharacterTable.json", "name_code", typeof(AttractiveCounselCharacterTable))] + [LoadRecord("AttractiveCounselCharacterTable.json", "name_code")] public readonly Dictionary AttractiveCounselCharacterTable = []; - [LoadRecord("AttractiveLevelRewardTable.json", "id", typeof(AttractiveLevelRewardTable))] + [LoadRecord("AttractiveLevelRewardTable.json", "id")] public readonly Dictionary AttractiveLevelReward = []; - [LoadRecord("SubQuestTable.json", "id", typeof(SubquestTable))] + [LoadRecord("SubQuestTable.json", "id")] public readonly Dictionary Subquests = []; - [LoadRecord("MessengerDialogTable.json", "id", typeof(MessengerDialogTable))] + [LoadRecord("MessengerDialogTable.json", "id")] public readonly Dictionary Messages = []; - [LoadRecord("MessengerConditionTriggerTable.json", "id", typeof(MessengerMsgConditionTable))] + [LoadRecord("MessengerConditionTriggerTable.json", "id")] public readonly Dictionary MessageConditions = []; - [LoadRecord("ScenarioRewardsTable.json", "condition_id", typeof(ScenarioRewardTable))] + [LoadRecord("ScenarioRewardsTable.json", "condition_id")] public readonly Dictionary ScenarioRewards = []; // Note: same data types are intentional - [LoadRecord("ProductOfferTable.json", "id", typeof(ProductOfferTable))] + [LoadRecord("ProductOfferTable.json", "id")] public readonly Dictionary ProductOffers = []; - [LoadRecord("PopupPackageListTable.json", "id", typeof(ProductOfferTable))] + [LoadRecord("PopupPackageListTable.json", "id")] public readonly Dictionary PopupPackages = []; - [LoadRecord("InterceptNormalTable.json", "id", typeof(InterceptionTable))] + [LoadRecord("InterceptNormalTable.json", "id")] public readonly Dictionary InterceptNormal = []; - [LoadRecord("InterceptSpecialTable.json", "id", typeof(InterceptionTable))] + [LoadRecord("InterceptSpecialTable.json", "id")] public readonly Dictionary InterceptSpecial = []; - [LoadRecord("ConditionRewardTable.json", "id", typeof(ConditionRewardTable))] + [LoadRecord("ConditionRewardTable.json", "id")] public readonly Dictionary ConditionRewards = []; - [LoadRecord("ItemConsumeTable.json", "id", typeof(ItemConsumeTable))] + [LoadRecord("ItemConsumeTable.json", "id")] public readonly Dictionary ConsumableItems = []; - [LoadRecord("ItemRandomTable.json", "id", typeof(RandomItemTable))] + [LoadRecord("ItemRandomTable.json", "id")] public readonly Dictionary RandomItem = []; - [LoadRecord("LostSectorTable.json", "id", typeof(LostSectorTable))] + [LoadRecord("LostSectorTable.json", "id")] public readonly Dictionary LostSector = []; - [LoadRecord("LostSectorStageTable.json", "id", typeof(LostSectorStageTable))] + [LoadRecord("LostSectorStageTable.json", "id")] public readonly Dictionary LostSectorStages = []; - [LoadRecord("ItemPieceTable.json", "id", typeof(ItemPieceTable))] + [LoadRecord("ItemPieceTable.json", "id")] public readonly Dictionary PieceItems = []; - [LoadRecord("GachaGradeProbTable.json", "id", typeof(GachaGradeProbTable))] + [LoadRecord("GachaGradeProbTable.json", "id")] public readonly Dictionary GachaGradeProb = []; - [LoadRecord("GachaListProbTable.json", "id", typeof(GachaListProbTable))] + [LoadRecord("GachaListProbTable.json", "id")] public readonly Dictionary GachaListProb = []; - [LoadRecord("RecycleResearchStatTable.json", "id", typeof(RecycleResearchStatTable))] + [LoadRecord("RecycleResearchStatTable.json", "id")] public readonly Dictionary RecycleResearchStats = []; - [LoadRecord("RecycleResearchLevelTable.json", "id", typeof(RecycleResearchLevelTable))] + [LoadRecord("RecycleResearchLevelTable.json", "id")] public readonly Dictionary RecycleResearchLevels = []; + static async Task BuildAsync() { await Load(); @@ -232,7 +238,10 @@ namespace EpinelPS.Data MpkSize = rawBytes2.Length; } - LoadGameData(filePath, GameConfig.Root.StaticData); + if (UseMemoryPack) + LoadGameData(mpkFilePath, GameConfig.Root.StaticDataMpk); + else + LoadGameData(filePath, GameConfig.Root.StaticData); if (MainZip == null) throw new Exception("failed to read zip file"); } @@ -371,25 +380,49 @@ namespace EpinelPS.Data } #endregion - public async Task LoadZip(string entry, IProgress bar) where T : new() + public async Task LoadZip(string entry, IProgress bar) where X : new() { - var fileEntry = MainZip.GetEntry(entry); - if (fileEntry == null) + try { - Logging.WriteLine(entry + " does not exist in static data", LogType.Error); - return new T(); + if (UseMemoryPack) entry = entry.Replace(".json", ".mpk"); + + var fileEntry = MainZip.GetEntry(entry); + if (fileEntry == null) + { + Logging.WriteLine(entry + " does not exist in static data", LogType.Error); + return []; + } + + X[]? deserializedObject; + + if (UseMemoryPack) + { + var stream = MainZip.GetInputStream(fileEntry); + deserializedObject = await MemoryPackSerializer.DeserializeAsync(stream); + } + else + { + + using StreamReader fileReader = new(MainZip.GetInputStream(fileEntry)); + string fileString = await fileReader.ReadToEndAsync(); + + var obj = JsonConvert.DeserializeObject>(fileString); + if (obj == null) throw new Exception("deserializeobject failed"); + deserializedObject = obj.records.ToArray(); + } + + if (deserializedObject == null) throw new Exception("failed to parse " + entry); + + currentFile++; + bar.Report((double)currentFile / totalFiles); + + return deserializedObject; + } + catch(Exception ex) + { + Logging.WriteLine($"Failed to parse {entry}:\n{ex.ToString()}\n", LogType.Error); + return []; } - - using StreamReader fileReader = new(MainZip.GetInputStream(fileEntry)); - string fileString = await fileReader.ReadToEndAsync(); - - T? deserializedObject = JsonConvert.DeserializeObject(fileString); - if (deserializedObject == null) throw new Exception("failed to parse " + entry); - - currentFile++; - bar.Report((double)currentFile / totalFiles); - - return deserializedObject; } public async Task Parse() @@ -397,6 +430,7 @@ namespace EpinelPS.Data using var progress = new ProgressBar(); totalFiles = GameDataInitializer.TotalFiles; + if (totalFiles == 0) throw new Exception("Source generator failed."); await GameDataInitializer.InitializeGameData(progress); @@ -407,9 +441,9 @@ namespace EpinelPS.Data item.Name.StartsWith("LostSectorMap/") ) { - var x = await LoadZip(item.Name, progress); + var x = await LoadZip(item.Name, progress); - foreach (var map in x.records) + foreach (var map in x) { MapData.Add(map.id, map); } @@ -540,14 +574,14 @@ namespace EpinelPS.Data internal IEnumerable GetStageIdsForChapter(int chapterNumber, bool normal) { - string mod = normal ? "Normal" : "Hard"; + ChapterMod mod = normal ? ChapterMod.Normal : ChapterMod.Hard; foreach (var item in StageDataRecords) { var data = item.Value; int chVal = data.chapter_id - 1; - if (chapterNumber == chVal && data.chapter_mod == mod && data.stage_type == "Main") + if (chapterNumber == chVal && data.mod == mod && data.stage_type == StageType.Main) { yield return data.id; } @@ -622,10 +656,10 @@ namespace EpinelPS.Data return false; } - internal string GetMapIdFromChapter(int chapter, int mod) + internal string GetMapIdFromChapter(int chapter, ChapterMod mod) { CampaignChapterRecord data = ChapterCampaignData[chapter - 1]; - if (mod != 0) + if (mod == ChapterMod.Hard) return data.hard_field_id; else return data.field_id; } diff --git a/EpinelPS/Data/JsonStaticData.cs b/EpinelPS/Data/JsonStaticData.cs index 9a9ad51..6a4c5b5 100644 --- a/EpinelPS/Data/JsonStaticData.cs +++ b/EpinelPS/Data/JsonStaticData.cs @@ -1,50 +1,148 @@ -namespace EpinelPS.Data +using System.Data; +using MemoryPack; + +namespace EpinelPS.Data { - public class MainQuestCompletionRecord + public class DataTable + { + public string version { get; set; } = ""; + public List records { get; set; } = []; + } + public enum Category + { + Campaign_View, + Outpost_View, + Ark_View, + Lobby_Enter, + Campaign_Enter, + Outpost_Building_Enter, + Ark_Marker, + Campaign_Clear, + Outpost_Select, + Tribe_Tower_Clear, + Tribe_Tower_Enter, + Tribe_Tower_View, + Run_Gacha, + Npc_Talk, + FieldObject_Collection, + End, + LostSector_View, + LostSector_Clear, + SimulationRoom_View, + EventQuest_Stage_Enter, + EventQuest_Stage_Clear, + EventQuest_Stage_Group_Clear, + EventQuest_Popup_Enter, + Normal_Chapter_View, + Field_Interaction_Action_Trigger, + FavoriteItemQuest_Stage_Enter, + FavoriteItemQuest_Stage_Clear, + FavoriteItemQuest_Stage_Group_Clear, + SimulationRoom_Select + } + public enum ScenarioType + { + None, + FieldTalk, + Dialog, + Balloon + } + public enum ChapterMod + { + Normal, + Hard + } + public enum StageCategory + { + Normal, + Story, + Hard, + Extra, + Boss + } + public enum StageType + { + None, + Main, + Sub, + Emergency, + EventQuest, + FavoriteItemQuest + } + public enum EquipmentRarityType + { + None, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10 + } + [MemoryPackable] + public partial class MainQuestCompletionRecord { public int id; public int group_id; - public string category = ""; + public Category category; public int condition_id; + public string condition_ui_localkey = ""; + public string shortcut_type = ""; + public int shortcut_value; + public string name_localkey = ""; + public string description_localkey = ""; public int next_main_quest_id = 0; public int reward_id = 0; + public ScenarioType scenario_type; + public string episode_id = ""; public int target_chapter_id; + public string header_bg_resource_id = ""; } - public class MainQuestCompletionTable - { - public List records = []; - } - public class CampaignStageRecord + [MemoryPackable] + public partial class CampaignStageRecord { public int id; public int chapter_id; - public string stage_category = ""; + public ChapterMod mod; + public int parent_id; + public int group_id; + public string name = ""; + public StageCategory stage_category; + public StageType stage_type; + public bool allow_autobattle; + public int enter_condition; + public int monster_stage_level; + public int dynobj_stage_level; + public int standard_battle_power; + public int statinc_groupid; + public bool allow_quickbattle; + public int fieldmonster_id; + public int spotid; public int reward_id = 0; - /// - /// Can be Normal or Hard - /// - public string chapter_mod = ""; - public string stage_type = ""; + public ScenarioType enter_scenario_type; public string enter_scenario = ""; + public ScenarioType exit_scenario_type; public string exit_scenario = ""; + public int current_outpost_battle_id; + public int cleared_battleid; + public int fixedCharacterid; + public int characterLevel; } - public class CampaignStageTable - { - public List records = []; - } - public class RewardTableRecord + [MemoryPackable] + public partial class RewardTableRecord { public int id; public int user_exp; public int character_exp; public RewardEntry[]? rewards; } - public class RewardTable - { - public List records = []; - } - public class RewardEntry + [MemoryPackable] + public partial class RewardEntry { /// /// example: 1000000 @@ -55,8 +153,6 @@ public int reward_id; public int reward_value; } - - public class ClearedTutorialData { public int id; @@ -66,12 +162,8 @@ public int NextId; public bool SaveTutorial; } - public class TutorialTable - { - public List records = []; - } - - public class CharacterLevelData + [MemoryPackable] + public partial class CharacterLevelData { /// /// level @@ -94,17 +186,13 @@ /// public int character_exp2 = 0; } - public class CharacterLevelTable - { - public List records = []; - } - public class TacticAcademyLessonReward { public int lesson_reward_id; public int lesson_reward_value; } - public class TacticAcademyLessonRecord + [MemoryPackable] + public partial class TacticAcademyLessonRecord { public int currency_id; public int currency_value; @@ -114,24 +202,16 @@ public TacticAcademyLessonReward[]? lesson_reward; } - public class TacticAcademyLessonTable - { - public List records = []; - } - - public class CampaignChapterRecord + [MemoryPackable] + public partial class CampaignChapterRecord { public int id; public int chapter; public string field_id = ""; public string hard_field_id = ""; } - public class CampaignChapterTable - { - public List records = []; - } - - public class CharacterRecord + [MemoryPackable] + public partial class CharacterRecord { public int id; public int piece_id; @@ -169,12 +249,9 @@ public bool prism_is_active; public bool is_detail_close; } - public class CharacterTable - { - public List records = []; - } - public class ItemEquipRecord + [MemoryPackable] + public partial class ItemEquipRecord { public int id; public string name_localkey = ""; @@ -204,12 +281,9 @@ public int option_slot; public int option_slot_success_ratio; } - public class ItemEquipTable - { - public List records = []; - } - public class FieldItemRecord + [MemoryPackable] + public partial class FieldItemRecord { public int id; public string item_type = ""; @@ -217,11 +291,9 @@ public bool is_final_reward; public string difficulty = ""; } - public class FieldItemTable - { - public List records = []; - } - public class JukeboxListRecord + + [MemoryPackable] + public partial class JukeboxListRecord { public int id; public int theme; @@ -235,12 +307,8 @@ public string get_info_value = ""; } - public class JukeboxListTable - { - public List records = []; - } - - public class JukeboxThemeRecord + [MemoryPackable] + public partial class JukeboxThemeRecord { public int id; public string name_localkey = ""; @@ -250,11 +318,8 @@ public string bg_color = ""; } - public class JukeboxThemeTable - { - public List records = []; - } - public class OutpostBattleTableRecord + [MemoryPackable] + public partial class OutpostBattleTableRecord { public int id; public int credit; @@ -262,12 +327,9 @@ public int character_exp2; public int user_exp; } - public class OutpostBattleTable - { - public List records = []; - } - public class GachaPriceGroup + [MemoryPackable] + public partial class GachaPriceGroup { public int gacha_price_type; public int gacha_price_value_count_1; @@ -275,7 +337,7 @@ public int gacha_price_value_count_10; } - public class GachaType + public partial class GachaType { public int id; public string type = ""; @@ -298,12 +360,8 @@ public int previous_gacha_id; } - public class GachaTypeTable - { - public List records = []; - } - - public class GachaGradeProbRecord + [MemoryPackable] + public partial class GachaGradeProbRecord { public int id; public int group_id; @@ -311,23 +369,16 @@ public int prob; public int gacha_list_id; } - public class GachaGradeProbTable - { - public List records = []; - } - - public class GachaListProbRecord + [MemoryPackable] + public partial class GachaListProbRecord { public int id; public int group_id; public int gacha_id; } - public class GachaListProbTable - { - public List records = []; - } - public class EventManager + [MemoryPackable] + public partial class EventManager { public int id; public string event_system_type = ""; @@ -348,23 +399,17 @@ public string active_type = ""; public string banner_print_type = ""; } + [MemoryPackable] + - public class EventManagerTable - { - public List records = []; - } - - public class LiveWallpaperRecord + public partial class LiveWallpaperRecord { public int id; public string livewallpaper_type = ""; } - - public class LiveWallpaperTable - { - public List records = []; - } - public class AlbumResourceRecord + [MemoryPackable] + + public partial class AlbumResourceRecord { public int id; public int sub_category_id; @@ -376,12 +421,9 @@ public string dialogtype = ""; } - public class AlbumResourceTable - { - public List records = []; - } - public class UserFrameTableRecord + [MemoryPackable] + public partial class UserFrameTableRecord { public int id; public string resource_id = ""; @@ -394,12 +436,9 @@ public bool is_sub_resource_prism; } - public class UserFrameTable - { - public List records = []; - } - public class ArchiveRecordManagerRecord + [MemoryPackable] + public partial class ArchiveRecordManagerRecord { public int id; public string record_type = ""; @@ -416,12 +455,9 @@ public string record_unlock_bg_addressable = ""; } - public class ArchiveRecordManagerTable - { - public List records = []; - } - public class ArchiveEventStoryRecord + [MemoryPackable] + public partial class ArchiveEventStoryRecord { public int id; public int event_id; @@ -433,12 +469,9 @@ public int archive_currency_item_id; } - public class ArchiveEventStoryTable - { - public List records = []; - } - public class ArchiveEventQuestRecord + [MemoryPackable] + public partial class ArchiveEventQuestRecord { public int id; public int event_quest_manager_id; @@ -450,12 +483,9 @@ public string end_scenario_id = ""; } - public class ArchiveEventQuestTable - { - public List records = []; - } - public class ArchiveEventDungeonStageRecord + [MemoryPackable] + public partial class ArchiveEventDungeonStageRecord { public int id; public int group; @@ -466,11 +496,8 @@ public bool is_repeat_clear; } - public class ArchiveEventDungeonStageTable - { - public List records = []; - } - public class UserTitleRecord + [MemoryPackable] + public partial class UserTitleRecord { public int id; public int order; @@ -483,32 +510,23 @@ public bool not_acquired_is_visible; } - public class UserTitleTable - { - public List records = []; - } - public class ArchiveMessengerConditionList + [MemoryPackable] + public partial class ArchiveMessengerConditionList { public string condition_type = ""; public int condition_id; } - - public class ArchiveMessengerConditionRecord + [MemoryPackable] + public partial class ArchiveMessengerConditionRecord { public int id; public int archive_messenger_group_id; public List archive_messenger_condition_list = []; public string tid = ""; } - - public class ArchiveMessengerConditionTable - { - public string version = ""; - public List records = []; - } - - public class CharacterStatRecord + [MemoryPackable] + public partial class CharacterStatRecord { public int id; public int group; @@ -520,12 +538,8 @@ public int level_bio_resist; } - public class CharacterStatTable - { - public List records = []; - } - - public class ItemMaterialRecord + [MemoryPackable] + public partial class ItemMaterialRecord { public int id; public string name_localkey = ""; @@ -540,12 +554,9 @@ public int stack_max; } - public class ItemMaterialTable - { - public List records = []; - } - public class SkillInfoRecord + [MemoryPackable] + public partial class SkillInfoRecord { public int id; public int group_id; @@ -564,11 +575,6 @@ public string description_value = ""; } - public class SkillInfoTable - { - public List records = []; - } - public class CostRecord { public int id; @@ -582,11 +588,8 @@ public int item_value; } - public class CostTable - { - public List records = []; - } - public class MidasProductRecord + [MemoryPackable] + public partial class MidasProductRecord { public int id; public string product_type = ""; @@ -597,10 +600,7 @@ public bool is_free; public string cost = ""; } - public class MidasProductTable - { - public List records = []; - } + public enum ShopCategoryType { None = 0, @@ -613,7 +613,8 @@ Mileage = 7, Trade = 8 } - public class TowerRecord + [MemoryPackable] + public partial class TowerRecord { public int id; public int floor; @@ -621,12 +622,9 @@ public int standard_battle_power; public int reward_id; } - public class TowerTable - { - public List records = []; - } - public class ItemEquipExpRecord + [MemoryPackable] + public partial class ItemEquipExpRecord { public int id; public int level; @@ -635,56 +633,39 @@ public int grade_core_id; } - public class ItemEquipExpTable - { - public List records = []; - } - public class ItemEquipGradeExpRecord + [MemoryPackable] + public partial class ItemEquipGradeExpRecord { public int id; - public int exp; - public string item_rare = ""; + public EquipmentRarityType item_rare; public int grade_core_id; + public int exp; } - - public class ItemEquipGradeExpTable - { - public List records = []; - } - - public class UserExpRecord + [MemoryPackable] + public partial class UserExpRecord { public int level; public int exp; public int reward_id; } - public class UserExpTable - { - public List records = []; - } - public class CharacterCostumeRecord + [MemoryPackable] + public partial class CharacterCostumeRecord { public int id; } - public class CharacterCostumeTable - { - public List records = []; - } - public class SideStoryStageRecord + [MemoryPackable] + public partial class SideStoryStageRecord { public int id; public int first_clear_reward; } - public class SideStoryStageTable - { - public List records = []; - } - public class TriggerRecord + [MemoryPackable] + public partial class TriggerRecord { public int id; public int condition_id; @@ -694,15 +675,13 @@ public bool print_value; public int before_trigger_id; } - public class TriggerTable - { - public List records = []; - } + public class InfracoreFunction { public int function; } - public class InfracoreRecord + [MemoryPackable] + public partial class InfracoreRecord { public int id; public int grade; @@ -710,22 +689,16 @@ public int infra_core_exp; public List function_list = []; } - public class InfracoreTable - { - public List records = []; - } - public class AttractiveCounselCharacterRecord + [MemoryPackable] + public partial class AttractiveCounselCharacterRecord { public int id; public int name_code; public int collect_reward_id; } - public class AttractiveCounselCharacterTable - { - public List records = []; - } - public class AttractiveLevelRewardRecord + [MemoryPackable] + public partial class AttractiveLevelRewardRecord { public int id; public int name_code; @@ -733,11 +706,8 @@ public int attractive_level; public int costume; } - public class AttractiveLevelRewardTable - { - public List records = []; - } - public class SubquestRecord + [MemoryPackable] + public partial class SubquestRecord { public int id; public int group_id; @@ -747,11 +717,9 @@ public string end_messenger_conversation_id = ""; public int before_sub_quest_id; } - public class SubquestTable - { - public List records = []; - } - public class MessengerDialogRecord + + [MemoryPackable] + public partial class MessengerDialogRecord { public string id = ""; public string conversation_id = ""; @@ -759,41 +727,36 @@ public bool is_opener; public int reward_id; } - public class MessengerDialogTable - { - public List records = []; - } - public class MessengerMsgConditionRecord + [MemoryPackable] + public partial class MessengerMsgConditionRecord { public int id; public string tid = ""; public int reward_id; } - public class MessengerMsgConditionTable + public enum ScenarioRewardCondition { - public List records = []; - } - public class ScenarioRewardRecord - { - public int id; - public string condition_id = ""; - public string condition_type = ""; - public int reward_id; - } - public class ScenarioRewardTable - { - public List records = []; + MainScenario, + AttractiveScenario } - public class ProductOfferRecord + [MemoryPackable] + public partial class ScenarioRewardRecord + { + public int id; + public ScenarioRewardCondition condition_type; + public string condition_id = ""; + public int reward_id; + } + + [MemoryPackable] + public partial class ProductOfferRecord { public int id; } - public class ProductOfferTable - { - public List records = []; - } - public class InterceptionRecord + + [MemoryPackable] + public partial class InterceptionRecord { public int id; public int group; @@ -801,11 +764,9 @@ public int percent_condition_reward_group; public long fixed_damage; } - public class InterceptionTable - { - public List records = []; - } - public class ConditionRewardRecord + + [MemoryPackable] + public partial class ConditionRewardRecord { public int id; public int group; @@ -814,10 +775,7 @@ public long value_max; public int reward_id; } - public class ConditionRewardTable - { - public List records = []; - } + public enum ItemSubType { BundleBox, @@ -829,7 +787,8 @@ ArcadeItem, EquipCombination } - public class ItemConsumeRecord + [MemoryPackable] + public partial class ItemConsumeRecord { public int id; public string use_type = ""; @@ -838,22 +797,18 @@ public int use_id; public int use_value; } - public class ItemConsumeTable - { - public List records = []; - } - public class ItemPieceRecord + + [MemoryPackable] + public partial class ItemPieceRecord { public int id; public string use_type = ""; public int use_id; public int use_value; } - public class ItemPieceTable - { - public List records = []; - } - public class RandomItemRecord + + [MemoryPackable] + public partial class RandomItemRecord { public int id; public int group_id; @@ -863,11 +818,9 @@ public int reward_value_max; public int ratio; } - public class RandomItemTable - { - public List records = []; - } - public class RecycleResearchStatRecord + + [MemoryPackable] + public partial class RecycleResearchStatRecord { public int id; public string recycle_type = ""; @@ -877,11 +830,9 @@ public int defense; public int hp; } - public class RecycleResearchStatTable - { - public List records = []; - } - public class RecycleResearchLevelRecord + + [MemoryPackable] + public partial class RecycleResearchLevelRecord { public int id; public string recycle_type = ""; @@ -890,16 +841,15 @@ public int item_id; public int item_value; } - public class RecycleResearchLevelTable - { - public List records = []; - } + public enum ContentOpenType { Stage, NonUpdate } - public class LostSectorRecord + + [MemoryPackable] + public partial class LostSectorRecord { public int id; public int sector; @@ -910,20 +860,14 @@ public int open_condition_value; } - public class LostSectorTable - { - public List records = []; - } - public class LostSectorStageRecord + [MemoryPackable] + public partial class LostSectorStageRecord { public int id; public bool is_use_quick_battle; public int sector; } - public class LostSectorStageTable - { - public List records = []; - } + public class ItemSpawner { @@ -936,14 +880,13 @@ public string positionId = ""; public int stageId; } - public class MapInfo + + [MemoryPackable] + public partial class MapInfo { public string id { get; set; } = ""; public List ItemSpawner { get; set; } = []; public List StageSpawner { get; set; } = []; } - public class MapInfoTable - { - public List records = []; - } + } diff --git a/EpinelPS/Data/LoadRecordAttribute.cs b/EpinelPS/Data/LoadRecordAttribute.cs index 43e5aa2..9ad2f88 100644 --- a/EpinelPS/Data/LoadRecordAttribute.cs +++ b/EpinelPS/Data/LoadRecordAttribute.cs @@ -2,10 +2,9 @@ namespace EpinelPS.Data { [System.AttributeUsage(System.AttributeTargets.Field)] - public class LoadRecordAttribute(string file, string primaryKey, Type tableType) : Attribute + public class LoadRecordAttribute(string file, string primaryKey) : Attribute { public string File { get; set; } = file; public string PrimaryKey { get; set; } = primaryKey; - public Type TableType { get; set; } = tableType; } } \ No newline at end of file diff --git a/EpinelPS/EpinelPS.csproj b/EpinelPS/EpinelPS.csproj index c59e31e..e9195cd 100644 --- a/EpinelPS/EpinelPS.csproj +++ b/EpinelPS/EpinelPS.csproj @@ -27,6 +27,7 @@ + diff --git a/EpinelPS/LobbyServer/Stage/ClearStage.cs b/EpinelPS/LobbyServer/Stage/ClearStage.cs index 3cb2a29..256add8 100644 --- a/EpinelPS/LobbyServer/Stage/ClearStage.cs +++ b/EpinelPS/LobbyServer/Stage/ClearStage.cs @@ -31,7 +31,7 @@ namespace EpinelPS.LobbyServer.Stage var response = new ResClearStage(); var clearedStage = GameData.Instance.GetStageData(StageId) ?? throw new Exception("cleared stage cannot be null"); - var stageMapId = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.chapter_mod); + var stageMapId = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.mod); if (user.FieldInfoNew.Count == 0) { @@ -89,33 +89,29 @@ namespace EpinelPS.LobbyServer.Stage }); } - if (clearedStage.stage_category == "Normal" || clearedStage.stage_category == "Boss" || clearedStage.stage_category == "Hard") + if (clearedStage.stage_category == StageCategory.Normal || clearedStage.stage_category == StageCategory.Boss || clearedStage.stage_category == StageCategory.Hard) { - if (clearedStage.chapter_mod == "Hard") + if (clearedStage.mod == ChapterMod.Hard) { if (StageId > user.LastHardStageCleared) user.LastHardStageCleared = StageId; } - else if (clearedStage.chapter_mod == "Normal") + else { if (StageId > user.LastNormalStageCleared) user.LastNormalStageCleared = StageId; } - else - { - Console.WriteLine("Unknown chapter mod " + clearedStage.chapter_mod); - } } - else if (clearedStage.stage_category == "Extra") + else if (clearedStage.stage_category == StageCategory.Extra) { - + // TODO } else { Console.WriteLine("Unknown stage category " + clearedStage.stage_category); } - if (clearedStage.stage_type != "Sub") + if (clearedStage.stage_type != StageType.Sub) { // add outpost reward level if unlocked if (user.MainQuestData.TryGetValue(21, out bool _)) @@ -137,9 +133,9 @@ namespace EpinelPS.LobbyServer.Stage // Mark chapter as completed if boss stage was completed - if (clearedStage.stage_category == "Boss" && clearedStage.stage_type == "Main") + if (clearedStage.stage_category == StageCategory.Boss && clearedStage.stage_type == StageType.Main) { - if (clearedStage.chapter_mod == "Hard") + if (clearedStage.mod == ChapterMod.Hard) user.AddTrigger(TriggerType.HardChapterClear, 1, clearedStage.chapter_id); else user.AddTrigger(TriggerType.ChapterClear, 1, clearedStage.chapter_id); diff --git a/EpinelPS/LobbyServer/Stage/EnterStage.cs b/EpinelPS/LobbyServer/Stage/EnterStage.cs index ffc14ca..f7ed2c6 100644 --- a/EpinelPS/LobbyServer/Stage/EnterStage.cs +++ b/EpinelPS/LobbyServer/Stage/EnterStage.cs @@ -15,9 +15,9 @@ namespace EpinelPS.LobbyServer.Stage var response = new ResEnterStage(); var clearedStage = GameData.Instance.GetStageData(req.StageId) ?? throw new Exception("cleared stage cannot be null"); - var map = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.chapter_id); + var map = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.mod); - if (clearedStage.stage_category == "Boss") + if (clearedStage.stage_category == StageCategory.Boss) { // When entering a boss stage, unlock boss information in campaign if (!user.FieldInfoNew.ContainsKey(map)) diff --git a/EpinelPS/LobbyServer/Stage/GetStage.cs b/EpinelPS/LobbyServer/Stage/GetStage.cs index 87faf91..1dec89a 100644 --- a/EpinelPS/LobbyServer/Stage/GetStage.cs +++ b/EpinelPS/LobbyServer/Stage/GetStage.cs @@ -12,7 +12,7 @@ namespace EpinelPS.LobbyServer.Stage ReqGetStageData req = await ReadData(); var user = GetUser(); - var mapId = GameData.Instance.GetMapIdFromChapter(req.Chapter, req.Mod); + var mapId = GameData.Instance.GetMapIdFromChapter(req.Chapter, (ChapterMod)req.Mod); ResGetStageData response = new() {