initial memorypack format support

This commit is contained in:
Mikhail Tyukin
2025-07-17 13:51:49 -04:00
parent 2c5d8acc93
commit 04a9fe29c4
10 changed files with 414 additions and 428 deletions

4
.editorconfig Normal file
View File

@@ -0,0 +1,4 @@
[*.cs]
# CA5397: Do not use deprecated SslProtocols values
dotnet_diagnostic.CA5397.severity = none

View File

@@ -42,12 +42,15 @@ public class LoadRecordInitializerGenerator : IIncrementalGenerator
if (context.SemanticModel.GetDeclaredSymbol(variable) is not IFieldSymbol symbol) if (context.SemanticModel.GetDeclaredSymbol(variable) is not IFieldSymbol symbol)
return null; return null;
if (symbol.Type is not INamedTypeSymbol namedSymbol)
return null;
foreach (var attr in symbol.GetAttributes()) 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 null;
return new LoadFieldInfo return new LoadFieldInfo
@@ -56,7 +59,7 @@ public class LoadRecordInitializerGenerator : IIncrementalGenerator
FieldName = symbol.Name, FieldName = symbol.Name,
FileName = fileName, FileName = fileName,
Key = key, 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("using System.Threading.Tasks;");
sb.AppendLine(); sb.AppendLine();
sb.AppendLine("namespace EpinelPS.Data;"); sb.AppendLine("namespace EpinelPS.Data;");
sb.AppendLine();
sb.AppendLine("public static class GameDataInitializer"); sb.AppendLine("public static class GameDataInitializer");
sb.AppendLine("{"); sb.AppendLine("{");
sb.AppendFormat($"public static int TotalFiles = {fieldInfos.Length};"); sb.AppendLine($"\tpublic static int TotalFiles = {fieldInfos.Length};");
sb.AppendLine(" public static async Task InitializeGameData(IProgress<double> progress = null)"); sb.AppendLine("\tpublic static async Task InitializeGameData(IProgress<double> progress = null)");
sb.AppendLine(" {"); sb.AppendLine("\t{");
foreach (var info in fieldInfos) foreach (var info in fieldInfos)
{ {
var tempVar = $"data_{info.FieldName}"; var tempVar = $"data_{info.FieldName}";
sb.AppendLine($" var {tempVar} = await {info.ContainingClass}.Instance.LoadZip<{info.RecordTypeName}>(\"{info.FileName}\", progress);"); sb.AppendLine($"\t\tvar {tempVar} = await {info.ContainingClass}.Instance.LoadZip<{info.RecordTypeName}>(\"{info.FileName}\", progress);");
sb.AppendLine($" foreach (var obj in {tempVar}.records)"); sb.AppendLine($"\t\tforeach (var obj in {tempVar})");
sb.AppendLine(" {"); sb.AppendLine("\t\t{");
sb.AppendLine($" {info.ContainingClass}.Instance.{info.FieldName}.Add(obj.{info.Key}, obj);"); sb.AppendLine($"\t\t\t{info.ContainingClass}.Instance.{info.FieldName}.Add(obj.{info.Key}, obj);");
sb.AppendLine(" }"); sb.AppendLine("\t\t}");
} }
sb.AppendLine(" }"); sb.AppendLine("\t}");
sb.AppendLine("}"); sb.AppendLine("}");
return sb.ToString(); return sb.ToString();

View File

@@ -13,6 +13,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{4BB2E7
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpinelPS.Analyzers", "EpinelPS.Analyzers\EpinelPS.Analyzers.csproj", "{E3B18A3D-B20B-447D-BCBE-12931E18B41E}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpinelPS.Analyzers", "EpinelPS.Analyzers\EpinelPS.Analyzers.csproj", "{E3B18A3D-B20B-447D-BCBE-12931E18B41E}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

View File

@@ -1,9 +1,11 @@
using EpinelPS.Utils; using System.Data;
using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Diagnostics; using System.Diagnostics;
using System.Security.Cryptography; using System.Security.Cryptography;
using EpinelPS.Utils;
using ICSharpCode.SharpZipLib.Zip;
using MemoryPack;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace EpinelPS.Data namespace EpinelPS.Data
{ {
@@ -33,171 +35,175 @@ namespace EpinelPS.Data
private int totalFiles = 1; private int totalFiles = 1;
private int currentFile = 0; 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<string, MapInfo> MapData = []; public readonly Dictionary<string, MapInfo> MapData = [];
[LoadRecord("MainQuestTable.json", "id", typeof(MainQuestCompletionTable))] [LoadRecord("MainQuestTable.json", "id")]
public readonly Dictionary<int, MainQuestCompletionRecord> QuestDataRecords = []; public readonly Dictionary<int, MainQuestCompletionRecord> QuestDataRecords = [];
[LoadRecord("CampaignStageTable.json", "id", typeof(CampaignStageTable))] [LoadRecord("CampaignStageTable.json", "id")]
public readonly Dictionary<int, CampaignStageRecord> StageDataRecords = []; public readonly Dictionary<int, CampaignStageRecord> StageDataRecords = [];
[LoadRecord("RewardTable.json", "id", typeof(RewardTable))] [LoadRecord("RewardTable.json", "id")]
public readonly Dictionary<int, RewardTableRecord> RewardDataRecords = []; public readonly Dictionary<int, RewardTableRecord> RewardDataRecords = [];
[LoadRecord("UserExpTable.json", "level", typeof(UserExpTable))] [LoadRecord("UserExpTable.json", "level")]
public readonly Dictionary<int, UserExpRecord> UserExpDataRecords = []; public readonly Dictionary<int, UserExpRecord> UserExpDataRecords = [];
[LoadRecord("CampaignChapterTable.json", "chapter", typeof(CampaignChapterTable))] [LoadRecord("CampaignChapterTable.json", "chapter")]
public readonly Dictionary<int, CampaignChapterRecord> ChapterCampaignData = []; public readonly Dictionary<int, CampaignChapterRecord> ChapterCampaignData = [];
[LoadRecord("CharacterCostumeTable.json", "id", typeof(CharacterCostumeTable))] [LoadRecord("CharacterCostumeTable.json", "id")]
public readonly Dictionary<int, CharacterCostumeRecord> CharacterCostumeTable = []; public readonly Dictionary<int, CharacterCostumeRecord> CharacterCostumeTable = [];
[LoadRecord("CharacterTable.json", "id", typeof(CharacterTable))] [LoadRecord("CharacterTable.json", "id")]
public readonly Dictionary<int, CharacterRecord> CharacterTable = []; public readonly Dictionary<int, CharacterRecord> CharacterTable = [];
[LoadRecord("ContentsTutorialTable.json", "id", typeof(TutorialTable))] [LoadRecord("ContentsTutorialTable.json", "id")]
public readonly Dictionary<int, ClearedTutorialData> TutorialTable = []; public readonly Dictionary<int, ClearedTutorialData> TutorialTable = [];
[LoadRecord("ItemEquipTable.json", "id", typeof(ItemEquipTable))] [LoadRecord("ItemEquipTable.json", "id")]
public readonly Dictionary<int, ItemEquipRecord> ItemEquipTable = []; public readonly Dictionary<int, ItemEquipRecord> ItemEquipTable = [];
[LoadRecord("ItemMaterialTable.json", "id", typeof(ItemMaterialTable))] [LoadRecord("ItemMaterialTable.json", "id")]
public readonly Dictionary<int, ItemMaterialRecord> itemMaterialTable = []; public readonly Dictionary<int, ItemMaterialRecord> itemMaterialTable = [];
[LoadRecord("ItemEquipExpTable.json", "id", typeof(ItemEquipExpTable))] [LoadRecord("ItemEquipExpTable.json", "id")]
public readonly Dictionary<int, ItemEquipExpRecord> itemEquipExpTable = []; public readonly Dictionary<int, ItemEquipExpRecord> itemEquipExpTable = [];
[LoadRecord("ItemEquipGradeExpTable.json", "id", typeof(ItemEquipGradeExpTable))] [LoadRecord("ItemEquipGradeExpTable.json", "id")]
public readonly Dictionary<int, ItemEquipGradeExpRecord> ItemEquipGradeExpTable = []; public readonly Dictionary<int, ItemEquipGradeExpRecord> ItemEquipGradeExpTable = [];
[LoadRecord("CharacterLevelTable.json", "level", typeof(CharacterLevelTable))] [LoadRecord("CharacterLevelTable.json", "level")]
public readonly Dictionary<int, CharacterLevelData> LevelData = []; public readonly Dictionary<int, CharacterLevelData> LevelData = [];
[LoadRecord("TacticAcademyFunctionTable.json", "id", typeof(TacticAcademyLessonTable))] [LoadRecord("TacticAcademyFunctionTable.json", "id")]
public readonly Dictionary<int, TacticAcademyLessonRecord> TacticAcademyLessons = []; public readonly Dictionary<int, TacticAcademyLessonRecord> TacticAcademyLessons = [];
[LoadRecord("SideStoryStageTable.json", "id", typeof(SideStoryStageTable))] [LoadRecord("SideStoryStageTable.json", "id")]
public readonly Dictionary<int, SideStoryStageRecord> SidestoryRewardTable = []; public readonly Dictionary<int, SideStoryStageRecord> SidestoryRewardTable = [];
[LoadRecord("FieldItemTable.json", "id", typeof(FieldItemTable))] [LoadRecord("FieldItemTable.json", "id")]
public readonly Dictionary<int, FieldItemRecord> FieldItems = []; public readonly Dictionary<int, FieldItemRecord> FieldItems = [];
[LoadRecord("OutpostBattleTable.json", "id", typeof(OutpostBattleTable))] [LoadRecord("OutpostBattleTable.json", "id")]
public readonly Dictionary<int, OutpostBattleTableRecord> OutpostBattle = []; public readonly Dictionary<int, OutpostBattleTableRecord> OutpostBattle = [];
[LoadRecord("JukeboxListTable.json", "id", typeof(JukeboxListTable))] [LoadRecord("JukeboxListTable.json", "id")]
public readonly Dictionary<int, JukeboxListRecord> jukeboxListDataRecords = []; public readonly Dictionary<int, JukeboxListRecord> jukeboxListDataRecords = [];
[LoadRecord("JukeboxThemeTable.json", "id", typeof(JukeboxThemeTable))] [LoadRecord("JukeboxThemeTable.json", "id")]
public readonly Dictionary<int, JukeboxThemeRecord> jukeboxThemeDataRecords = []; public readonly Dictionary<int, JukeboxThemeRecord> jukeboxThemeDataRecords = [];
[LoadRecord("GachaTypeTable.json", "id", typeof(GachaTypeTable))] [LoadRecord("GachaTypeTable.json", "id")]
public readonly Dictionary<int, GachaType> gachaTypes = []; public readonly Dictionary<int, GachaType> gachaTypes = [];
[LoadRecord("EventManagerTable.json", "id", typeof(EventManagerTable))] [LoadRecord("EventManagerTable.json", "id")]
public readonly Dictionary<int, EventManager> eventManagers = []; public readonly Dictionary<int, EventManager> eventManagers = [];
[LoadRecord("LiveWallpaperTable.json", "id", typeof(LiveWallpaperTable))] [LoadRecord("LiveWallpaperTable.json", "id")]
public readonly Dictionary<int, LiveWallpaperRecord> lwptablemgrs = []; public readonly Dictionary<int, LiveWallpaperRecord> lwptablemgrs = [];
[LoadRecord("AlbumResourceTable.json", "id", typeof(AlbumResourceTable))] [LoadRecord("AlbumResourceTable.json", "id")]
public readonly Dictionary<int, AlbumResourceRecord> albumResourceRecords = []; public readonly Dictionary<int, AlbumResourceRecord> albumResourceRecords = [];
[LoadRecord("UserFrameTable.json", "id", typeof(UserFrameTable))] [LoadRecord("UserFrameTable.json", "id")]
public readonly Dictionary<int, UserFrameTableRecord> userFrameTable = []; public readonly Dictionary<int, UserFrameTableRecord> userFrameTable = [];
[LoadRecord("ArchiveRecordManagerTable.json", "id", typeof(ArchiveRecordManagerTable))] [LoadRecord("ArchiveRecordManagerTable.json", "id")]
public readonly Dictionary<int, ArchiveRecordManagerRecord> archiveRecordManagerTable = []; public readonly Dictionary<int, ArchiveRecordManagerRecord> archiveRecordManagerTable = [];
[LoadRecord("ArchiveEventStoryTable.json", "id", typeof(ArchiveEventStoryTable))] [LoadRecord("ArchiveEventStoryTable.json", "id")]
public readonly Dictionary<int, ArchiveEventStoryRecord> archiveEventStoryRecords = []; public readonly Dictionary<int, ArchiveEventStoryRecord> archiveEventStoryRecords = [];
[LoadRecord("ArchiveEventQuestTable.json", "id", typeof(ArchiveEventQuestTable))] [LoadRecord("ArchiveEventQuestTable.json", "id")]
public readonly Dictionary<int, ArchiveEventQuestRecord> archiveEventQuestRecords = []; public readonly Dictionary<int, ArchiveEventQuestRecord> archiveEventQuestRecords = [];
[LoadRecord("ArchiveEventDungeonStageTable.json", "id", typeof(ArchiveEventDungeonStageTable))] [LoadRecord("ArchiveEventDungeonStageTable.json", "id")]
public readonly Dictionary<int, ArchiveEventDungeonStageRecord> archiveEventDungeonStageRecords = []; public readonly Dictionary<int, ArchiveEventDungeonStageRecord> archiveEventDungeonStageRecords = [];
[LoadRecord("UserTitleTable.json", "id", typeof(UserTitleTable))] [LoadRecord("UserTitleTable.json", "id")]
public readonly Dictionary<int, UserTitleRecord> userTitleRecords = []; public readonly Dictionary<int, UserTitleRecord> userTitleRecords = [];
[LoadRecord("ArchiveMessengerConditionTable.json", "id", typeof(ArchiveMessengerConditionTable))] [LoadRecord("ArchiveMessengerConditionTable.json", "id")]
public readonly Dictionary<int, ArchiveMessengerConditionRecord> archiveMessengerConditionRecords = []; public readonly Dictionary<int, ArchiveMessengerConditionRecord> archiveMessengerConditionRecords = [];
[LoadRecord("CharacterStatTable.json", "id", typeof(CharacterStatTable))] [LoadRecord("CharacterStatTable.json", "id")]
public readonly Dictionary<int, CharacterStatRecord> characterStatTable = []; public readonly Dictionary<int, CharacterStatRecord> characterStatTable = [];
[LoadRecord("SkillInfoTable.json", "id", typeof(SkillInfoTable))] [LoadRecord("SkillInfoTable.json", "id")]
public readonly Dictionary<int, SkillInfoRecord> skillInfoTable = []; public readonly Dictionary<int, SkillInfoRecord> skillInfoTable = [];
[LoadRecord("CostTable.json", "id", typeof(CostTable))] [LoadRecord("CostTable.json", "id")]
public readonly Dictionary<int, CostRecord> costTable = []; public readonly Dictionary<int, CostRecord> costTable = [];
[LoadRecord("MidasProductTable.json", "midas_product_id_proximabeta", typeof(MidasProductTable))] [LoadRecord("MidasProductTable.json", "midas_product_id_proximabeta")]
public readonly Dictionary<string, MidasProductRecord> mediasProductTable = []; public readonly Dictionary<string, MidasProductRecord> mediasProductTable = [];
[LoadRecord("TowerTable.json", "id", typeof(TowerTable))] [LoadRecord("TowerTable.json", "id")]
public readonly Dictionary<int, TowerRecord> towerTable = []; public readonly Dictionary<int, TowerRecord> towerTable = [];
[LoadRecord("TriggerTable.json", "id", typeof(TriggerTable))] [LoadRecord("TriggerTable.json", "id")]
public readonly Dictionary<int, TriggerRecord> TriggerTable = []; public readonly Dictionary<int, TriggerRecord> TriggerTable = [];
[LoadRecord("InfraCoreGradeTable.json", "id", typeof(InfracoreTable))] [LoadRecord("InfraCoreGradeTable.json", "id")]
public readonly Dictionary<int, InfracoreRecord> InfracoreTable = []; public readonly Dictionary<int, InfracoreRecord> InfracoreTable = [];
[LoadRecord("AttractiveCounselCharacterTable.json", "name_code", typeof(AttractiveCounselCharacterTable))] [LoadRecord("AttractiveCounselCharacterTable.json", "name_code")]
public readonly Dictionary<int, AttractiveCounselCharacterRecord> AttractiveCounselCharacterTable = []; public readonly Dictionary<int, AttractiveCounselCharacterRecord> AttractiveCounselCharacterTable = [];
[LoadRecord("AttractiveLevelRewardTable.json", "id", typeof(AttractiveLevelRewardTable))] [LoadRecord("AttractiveLevelRewardTable.json", "id")]
public readonly Dictionary<int, AttractiveLevelRewardRecord> AttractiveLevelReward = []; public readonly Dictionary<int, AttractiveLevelRewardRecord> AttractiveLevelReward = [];
[LoadRecord("SubQuestTable.json", "id", typeof(SubquestTable))] [LoadRecord("SubQuestTable.json", "id")]
public readonly Dictionary<int, SubquestRecord> Subquests = []; public readonly Dictionary<int, SubquestRecord> Subquests = [];
[LoadRecord("MessengerDialogTable.json", "id", typeof(MessengerDialogTable))] [LoadRecord("MessengerDialogTable.json", "id")]
public readonly Dictionary<string, MessengerDialogRecord> Messages = []; public readonly Dictionary<string, MessengerDialogRecord> Messages = [];
[LoadRecord("MessengerConditionTriggerTable.json", "id", typeof(MessengerMsgConditionTable))] [LoadRecord("MessengerConditionTriggerTable.json", "id")]
public readonly Dictionary<int, MessengerMsgConditionRecord> MessageConditions = []; public readonly Dictionary<int, MessengerMsgConditionRecord> MessageConditions = [];
[LoadRecord("ScenarioRewardsTable.json", "condition_id", typeof(ScenarioRewardTable))] [LoadRecord("ScenarioRewardsTable.json", "condition_id")]
public readonly Dictionary<string, ScenarioRewardRecord> ScenarioRewards = []; public readonly Dictionary<string, ScenarioRewardRecord> ScenarioRewards = [];
// Note: same data types are intentional // Note: same data types are intentional
[LoadRecord("ProductOfferTable.json", "id", typeof(ProductOfferTable))] [LoadRecord("ProductOfferTable.json", "id")]
public readonly Dictionary<int, ProductOfferRecord> ProductOffers = []; public readonly Dictionary<int, ProductOfferRecord> ProductOffers = [];
[LoadRecord("PopupPackageListTable.json", "id", typeof(ProductOfferTable))] [LoadRecord("PopupPackageListTable.json", "id")]
public readonly Dictionary<int, ProductOfferRecord> PopupPackages = []; public readonly Dictionary<int, ProductOfferRecord> PopupPackages = [];
[LoadRecord("InterceptNormalTable.json", "id", typeof(InterceptionTable))] [LoadRecord("InterceptNormalTable.json", "id")]
public readonly Dictionary<int, InterceptionRecord> InterceptNormal = []; public readonly Dictionary<int, InterceptionRecord> InterceptNormal = [];
[LoadRecord("InterceptSpecialTable.json", "id", typeof(InterceptionTable))] [LoadRecord("InterceptSpecialTable.json", "id")]
public readonly Dictionary<int, InterceptionRecord> InterceptSpecial = []; public readonly Dictionary<int, InterceptionRecord> InterceptSpecial = [];
[LoadRecord("ConditionRewardTable.json", "id", typeof(ConditionRewardTable))] [LoadRecord("ConditionRewardTable.json", "id")]
public readonly Dictionary<int, ConditionRewardRecord> ConditionRewards = []; public readonly Dictionary<int, ConditionRewardRecord> ConditionRewards = [];
[LoadRecord("ItemConsumeTable.json", "id", typeof(ItemConsumeTable))] [LoadRecord("ItemConsumeTable.json", "id")]
public readonly Dictionary<int, ItemConsumeRecord> ConsumableItems = []; public readonly Dictionary<int, ItemConsumeRecord> ConsumableItems = [];
[LoadRecord("ItemRandomTable.json", "id", typeof(RandomItemTable))] [LoadRecord("ItemRandomTable.json", "id")]
public readonly Dictionary<int, RandomItemRecord> RandomItem = []; public readonly Dictionary<int, RandomItemRecord> RandomItem = [];
[LoadRecord("LostSectorTable.json", "id", typeof(LostSectorTable))] [LoadRecord("LostSectorTable.json", "id")]
public readonly Dictionary<int, LostSectorRecord> LostSector = []; public readonly Dictionary<int, LostSectorRecord> LostSector = [];
[LoadRecord("LostSectorStageTable.json", "id", typeof(LostSectorStageTable))] [LoadRecord("LostSectorStageTable.json", "id")]
public readonly Dictionary<int, LostSectorStageRecord> LostSectorStages = []; public readonly Dictionary<int, LostSectorStageRecord> LostSectorStages = [];
[LoadRecord("ItemPieceTable.json", "id", typeof(ItemPieceTable))] [LoadRecord("ItemPieceTable.json", "id")]
public readonly Dictionary<int, ItemPieceRecord> PieceItems = []; public readonly Dictionary<int, ItemPieceRecord> PieceItems = [];
[LoadRecord("GachaGradeProbTable.json", "id", typeof(GachaGradeProbTable))] [LoadRecord("GachaGradeProbTable.json", "id")]
public readonly Dictionary<int, GachaGradeProbRecord> GachaGradeProb = []; public readonly Dictionary<int, GachaGradeProbRecord> GachaGradeProb = [];
[LoadRecord("GachaListProbTable.json", "id", typeof(GachaListProbTable))] [LoadRecord("GachaListProbTable.json", "id")]
public readonly Dictionary<int, GachaListProbRecord> GachaListProb = []; public readonly Dictionary<int, GachaListProbRecord> GachaListProb = [];
[LoadRecord("RecycleResearchStatTable.json", "id", typeof(RecycleResearchStatTable))] [LoadRecord("RecycleResearchStatTable.json", "id")]
public readonly Dictionary<int, RecycleResearchStatRecord> RecycleResearchStats = []; public readonly Dictionary<int, RecycleResearchStatRecord> RecycleResearchStats = [];
[LoadRecord("RecycleResearchLevelTable.json", "id", typeof(RecycleResearchLevelTable))] [LoadRecord("RecycleResearchLevelTable.json", "id")]
public readonly Dictionary<int, RecycleResearchLevelRecord> RecycleResearchLevels = []; public readonly Dictionary<int, RecycleResearchLevelRecord> RecycleResearchLevels = [];
static async Task<GameData> BuildAsync() static async Task<GameData> BuildAsync()
{ {
await Load(); await Load();
@@ -232,7 +238,10 @@ namespace EpinelPS.Data
MpkSize = rawBytes2.Length; 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"); if (MainZip == null) throw new Exception("failed to read zip file");
} }
@@ -371,25 +380,49 @@ namespace EpinelPS.Data
} }
#endregion #endregion
public async Task<T> LoadZip<T>(string entry, IProgress<double> bar) where T : new() public async Task<X[]> LoadZip<X>(string entry, IProgress<double> bar) where X : new()
{ {
var fileEntry = MainZip.GetEntry(entry); try
if (fileEntry == null)
{ {
Logging.WriteLine(entry + " does not exist in static data", LogType.Error); if (UseMemoryPack) entry = entry.Replace(".json", ".mpk");
return new T();
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<X[]>(stream);
}
else
{
using StreamReader fileReader = new(MainZip.GetInputStream(fileEntry));
string fileString = await fileReader.ReadToEndAsync();
var obj = JsonConvert.DeserializeObject<DataTable<X>>(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<T>(fileString);
if (deserializedObject == null) throw new Exception("failed to parse " + entry);
currentFile++;
bar.Report((double)currentFile / totalFiles);
return deserializedObject;
} }
public async Task Parse() public async Task Parse()
@@ -397,6 +430,7 @@ namespace EpinelPS.Data
using var progress = new ProgressBar(); using var progress = new ProgressBar();
totalFiles = GameDataInitializer.TotalFiles; totalFiles = GameDataInitializer.TotalFiles;
if (totalFiles == 0) throw new Exception("Source generator failed.");
await GameDataInitializer.InitializeGameData(progress); await GameDataInitializer.InitializeGameData(progress);
@@ -407,9 +441,9 @@ namespace EpinelPS.Data
item.Name.StartsWith("LostSectorMap/") item.Name.StartsWith("LostSectorMap/")
) )
{ {
var x = await LoadZip<MapInfoTable>(item.Name, progress); var x = await LoadZip<MapInfo>(item.Name, progress);
foreach (var map in x.records) foreach (var map in x)
{ {
MapData.Add(map.id, map); MapData.Add(map.id, map);
} }
@@ -540,14 +574,14 @@ namespace EpinelPS.Data
internal IEnumerable<int> GetStageIdsForChapter(int chapterNumber, bool normal) internal IEnumerable<int> GetStageIdsForChapter(int chapterNumber, bool normal)
{ {
string mod = normal ? "Normal" : "Hard"; ChapterMod mod = normal ? ChapterMod.Normal : ChapterMod.Hard;
foreach (var item in StageDataRecords) foreach (var item in StageDataRecords)
{ {
var data = item.Value; var data = item.Value;
int chVal = data.chapter_id - 1; 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; yield return data.id;
} }
@@ -622,10 +656,10 @@ namespace EpinelPS.Data
return false; return false;
} }
internal string GetMapIdFromChapter(int chapter, int mod) internal string GetMapIdFromChapter(int chapter, ChapterMod mod)
{ {
CampaignChapterRecord data = ChapterCampaignData[chapter - 1]; CampaignChapterRecord data = ChapterCampaignData[chapter - 1];
if (mod != 0) if (mod == ChapterMod.Hard)
return data.hard_field_id; return data.hard_field_id;
else return data.field_id; else return data.field_id;
} }

View File

@@ -1,50 +1,148 @@
namespace EpinelPS.Data using System.Data;
using MemoryPack;
namespace EpinelPS.Data
{ {
public class MainQuestCompletionRecord public class DataTable<T>
{
public string version { get; set; } = "";
public List<T> 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 id;
public int group_id; public int group_id;
public string category = ""; public Category category;
public int condition_id; 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 next_main_quest_id = 0;
public int reward_id = 0; public int reward_id = 0;
public ScenarioType scenario_type;
public string episode_id = "";
public int target_chapter_id; public int target_chapter_id;
public string header_bg_resource_id = "";
} }
public class MainQuestCompletionTable [MemoryPackable]
{ public partial class CampaignStageRecord
public List<MainQuestCompletionRecord> records = [];
}
public class CampaignStageRecord
{ {
public int id; public int id;
public int chapter_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; public int reward_id = 0;
/// <summary> public ScenarioType enter_scenario_type;
/// Can be Normal or Hard
/// </summary>
public string chapter_mod = "";
public string stage_type = "";
public string enter_scenario = ""; public string enter_scenario = "";
public ScenarioType exit_scenario_type;
public string exit_scenario = ""; public string exit_scenario = "";
public int current_outpost_battle_id;
public int cleared_battleid;
public int fixedCharacterid;
public int characterLevel;
} }
public class CampaignStageTable [MemoryPackable]
{ public partial class RewardTableRecord
public List<CampaignStageRecord> records = [];
}
public class RewardTableRecord
{ {
public int id; public int id;
public int user_exp; public int user_exp;
public int character_exp; public int character_exp;
public RewardEntry[]? rewards; public RewardEntry[]? rewards;
} }
public class RewardTable
{
public List<RewardTableRecord> records = [];
}
public class RewardEntry [MemoryPackable]
public partial class RewardEntry
{ {
/// <summary> /// <summary>
/// example: 1000000 /// example: 1000000
@@ -55,8 +153,6 @@
public int reward_id; public int reward_id;
public int reward_value; public int reward_value;
} }
public class ClearedTutorialData public class ClearedTutorialData
{ {
public int id; public int id;
@@ -66,12 +162,8 @@
public int NextId; public int NextId;
public bool SaveTutorial; public bool SaveTutorial;
} }
public class TutorialTable [MemoryPackable]
{ public partial class CharacterLevelData
public List<ClearedTutorialData> records = [];
}
public class CharacterLevelData
{ {
/// <summary> /// <summary>
/// level /// level
@@ -94,17 +186,13 @@
/// </summary> /// </summary>
public int character_exp2 = 0; public int character_exp2 = 0;
} }
public class CharacterLevelTable
{
public List<CharacterLevelData> records = [];
}
public class TacticAcademyLessonReward public class TacticAcademyLessonReward
{ {
public int lesson_reward_id; public int lesson_reward_id;
public int lesson_reward_value; public int lesson_reward_value;
} }
public class TacticAcademyLessonRecord [MemoryPackable]
public partial class TacticAcademyLessonRecord
{ {
public int currency_id; public int currency_id;
public int currency_value; public int currency_value;
@@ -114,24 +202,16 @@
public TacticAcademyLessonReward[]? lesson_reward; public TacticAcademyLessonReward[]? lesson_reward;
} }
public class TacticAcademyLessonTable [MemoryPackable]
{ public partial class CampaignChapterRecord
public List<TacticAcademyLessonRecord> records = [];
}
public class CampaignChapterRecord
{ {
public int id; public int id;
public int chapter; public int chapter;
public string field_id = ""; public string field_id = "";
public string hard_field_id = ""; public string hard_field_id = "";
} }
public class CampaignChapterTable [MemoryPackable]
{ public partial class CharacterRecord
public List<CampaignChapterRecord> records = [];
}
public class CharacterRecord
{ {
public int id; public int id;
public int piece_id; public int piece_id;
@@ -169,12 +249,9 @@
public bool prism_is_active; public bool prism_is_active;
public bool is_detail_close; public bool is_detail_close;
} }
public class CharacterTable
{
public List<CharacterRecord> records = [];
}
public class ItemEquipRecord [MemoryPackable]
public partial class ItemEquipRecord
{ {
public int id; public int id;
public string name_localkey = ""; public string name_localkey = "";
@@ -204,12 +281,9 @@
public int option_slot; public int option_slot;
public int option_slot_success_ratio; public int option_slot_success_ratio;
} }
public class ItemEquipTable
{
public List<ItemEquipRecord> records = [];
}
public class FieldItemRecord [MemoryPackable]
public partial class FieldItemRecord
{ {
public int id; public int id;
public string item_type = ""; public string item_type = "";
@@ -217,11 +291,9 @@
public bool is_final_reward; public bool is_final_reward;
public string difficulty = ""; public string difficulty = "";
} }
public class FieldItemTable
{ [MemoryPackable]
public List<FieldItemRecord> records = []; public partial class JukeboxListRecord
}
public class JukeboxListRecord
{ {
public int id; public int id;
public int theme; public int theme;
@@ -235,12 +307,8 @@
public string get_info_value = ""; public string get_info_value = "";
} }
public class JukeboxListTable [MemoryPackable]
{ public partial class JukeboxThemeRecord
public List<JukeboxListRecord> records = [];
}
public class JukeboxThemeRecord
{ {
public int id; public int id;
public string name_localkey = ""; public string name_localkey = "";
@@ -250,11 +318,8 @@
public string bg_color = ""; public string bg_color = "";
} }
public class JukeboxThemeTable [MemoryPackable]
{ public partial class OutpostBattleTableRecord
public List<JukeboxThemeRecord> records = [];
}
public class OutpostBattleTableRecord
{ {
public int id; public int id;
public int credit; public int credit;
@@ -262,12 +327,9 @@
public int character_exp2; public int character_exp2;
public int user_exp; public int user_exp;
} }
public class OutpostBattleTable
{
public List<OutpostBattleTableRecord> records = [];
}
public class GachaPriceGroup [MemoryPackable]
public partial class GachaPriceGroup
{ {
public int gacha_price_type; public int gacha_price_type;
public int gacha_price_value_count_1; public int gacha_price_value_count_1;
@@ -275,7 +337,7 @@
public int gacha_price_value_count_10; public int gacha_price_value_count_10;
} }
public class GachaType public partial class GachaType
{ {
public int id; public int id;
public string type = ""; public string type = "";
@@ -298,12 +360,8 @@
public int previous_gacha_id; public int previous_gacha_id;
} }
public class GachaTypeTable [MemoryPackable]
{ public partial class GachaGradeProbRecord
public List<GachaType> records = [];
}
public class GachaGradeProbRecord
{ {
public int id; public int id;
public int group_id; public int group_id;
@@ -311,23 +369,16 @@
public int prob; public int prob;
public int gacha_list_id; public int gacha_list_id;
} }
public class GachaGradeProbTable [MemoryPackable]
{ public partial class GachaListProbRecord
public List<GachaGradeProbRecord> records = [];
}
public class GachaListProbRecord
{ {
public int id; public int id;
public int group_id; public int group_id;
public int gacha_id; public int gacha_id;
} }
public class GachaListProbTable
{
public List<GachaListProbRecord> records = [];
}
public class EventManager [MemoryPackable]
public partial class EventManager
{ {
public int id; public int id;
public string event_system_type = ""; public string event_system_type = "";
@@ -348,23 +399,17 @@
public string active_type = ""; public string active_type = "";
public string banner_print_type = ""; public string banner_print_type = "";
} }
[MemoryPackable]
public class EventManagerTable public partial class LiveWallpaperRecord
{
public List<EventManager> records = [];
}
public class LiveWallpaperRecord
{ {
public int id; public int id;
public string livewallpaper_type = ""; public string livewallpaper_type = "";
} }
[MemoryPackable]
public class LiveWallpaperTable
{ public partial class AlbumResourceRecord
public List<LiveWallpaperRecord> records = [];
}
public class AlbumResourceRecord
{ {
public int id; public int id;
public int sub_category_id; public int sub_category_id;
@@ -376,12 +421,9 @@
public string dialogtype = ""; public string dialogtype = "";
} }
public class AlbumResourceTable
{
public List<AlbumResourceRecord> records = [];
}
public class UserFrameTableRecord [MemoryPackable]
public partial class UserFrameTableRecord
{ {
public int id; public int id;
public string resource_id = ""; public string resource_id = "";
@@ -394,12 +436,9 @@
public bool is_sub_resource_prism; public bool is_sub_resource_prism;
} }
public class UserFrameTable
{
public List<UserFrameTableRecord> records = [];
}
public class ArchiveRecordManagerRecord [MemoryPackable]
public partial class ArchiveRecordManagerRecord
{ {
public int id; public int id;
public string record_type = ""; public string record_type = "";
@@ -416,12 +455,9 @@
public string record_unlock_bg_addressable = ""; public string record_unlock_bg_addressable = "";
} }
public class ArchiveRecordManagerTable
{
public List<ArchiveRecordManagerRecord> records = [];
}
public class ArchiveEventStoryRecord [MemoryPackable]
public partial class ArchiveEventStoryRecord
{ {
public int id; public int id;
public int event_id; public int event_id;
@@ -433,12 +469,9 @@
public int archive_currency_item_id; public int archive_currency_item_id;
} }
public class ArchiveEventStoryTable
{
public List<ArchiveEventStoryRecord> records = [];
}
public class ArchiveEventQuestRecord [MemoryPackable]
public partial class ArchiveEventQuestRecord
{ {
public int id; public int id;
public int event_quest_manager_id; public int event_quest_manager_id;
@@ -450,12 +483,9 @@
public string end_scenario_id = ""; public string end_scenario_id = "";
} }
public class ArchiveEventQuestTable
{
public List<ArchiveEventQuestRecord> records = [];
}
public class ArchiveEventDungeonStageRecord [MemoryPackable]
public partial class ArchiveEventDungeonStageRecord
{ {
public int id; public int id;
public int group; public int group;
@@ -466,11 +496,8 @@
public bool is_repeat_clear; public bool is_repeat_clear;
} }
public class ArchiveEventDungeonStageTable [MemoryPackable]
{ public partial class UserTitleRecord
public List<ArchiveEventDungeonStageRecord> records = [];
}
public class UserTitleRecord
{ {
public int id; public int id;
public int order; public int order;
@@ -483,32 +510,23 @@
public bool not_acquired_is_visible; public bool not_acquired_is_visible;
} }
public class UserTitleTable
{
public List<UserTitleRecord> records = [];
}
public class ArchiveMessengerConditionList [MemoryPackable]
public partial class ArchiveMessengerConditionList
{ {
public string condition_type = ""; public string condition_type = "";
public int condition_id; public int condition_id;
} }
[MemoryPackable]
public class ArchiveMessengerConditionRecord public partial class ArchiveMessengerConditionRecord
{ {
public int id; public int id;
public int archive_messenger_group_id; public int archive_messenger_group_id;
public List<ArchiveMessengerConditionList> archive_messenger_condition_list = []; public List<ArchiveMessengerConditionList> archive_messenger_condition_list = [];
public string tid = ""; public string tid = "";
} }
[MemoryPackable]
public class ArchiveMessengerConditionTable public partial class CharacterStatRecord
{
public string version = "";
public List<ArchiveMessengerConditionRecord> records = [];
}
public class CharacterStatRecord
{ {
public int id; public int id;
public int group; public int group;
@@ -520,12 +538,8 @@
public int level_bio_resist; public int level_bio_resist;
} }
public class CharacterStatTable [MemoryPackable]
{ public partial class ItemMaterialRecord
public List<CharacterStatRecord> records = [];
}
public class ItemMaterialRecord
{ {
public int id; public int id;
public string name_localkey = ""; public string name_localkey = "";
@@ -540,12 +554,9 @@
public int stack_max; public int stack_max;
} }
public class ItemMaterialTable
{
public List<ItemMaterialRecord> records = [];
}
public class SkillInfoRecord [MemoryPackable]
public partial class SkillInfoRecord
{ {
public int id; public int id;
public int group_id; public int group_id;
@@ -564,11 +575,6 @@
public string description_value = ""; public string description_value = "";
} }
public class SkillInfoTable
{
public List<SkillInfoRecord> records = [];
}
public class CostRecord public class CostRecord
{ {
public int id; public int id;
@@ -582,11 +588,8 @@
public int item_value; public int item_value;
} }
public class CostTable [MemoryPackable]
{ public partial class MidasProductRecord
public List<CostRecord> records = [];
}
public class MidasProductRecord
{ {
public int id; public int id;
public string product_type = ""; public string product_type = "";
@@ -597,10 +600,7 @@
public bool is_free; public bool is_free;
public string cost = ""; public string cost = "";
} }
public class MidasProductTable
{
public List<MidasProductRecord> records = [];
}
public enum ShopCategoryType public enum ShopCategoryType
{ {
None = 0, None = 0,
@@ -613,7 +613,8 @@
Mileage = 7, Mileage = 7,
Trade = 8 Trade = 8
} }
public class TowerRecord [MemoryPackable]
public partial class TowerRecord
{ {
public int id; public int id;
public int floor; public int floor;
@@ -621,12 +622,9 @@
public int standard_battle_power; public int standard_battle_power;
public int reward_id; public int reward_id;
} }
public class TowerTable
{
public List<TowerRecord> records = [];
}
public class ItemEquipExpRecord [MemoryPackable]
public partial class ItemEquipExpRecord
{ {
public int id; public int id;
public int level; public int level;
@@ -635,56 +633,39 @@
public int grade_core_id; public int grade_core_id;
} }
public class ItemEquipExpTable
{
public List<ItemEquipExpRecord> records = [];
}
public class ItemEquipGradeExpRecord [MemoryPackable]
public partial class ItemEquipGradeExpRecord
{ {
public int id; public int id;
public int exp; public EquipmentRarityType item_rare;
public string item_rare = "";
public int grade_core_id; public int grade_core_id;
public int exp;
} }
[MemoryPackable]
public class ItemEquipGradeExpTable public partial class UserExpRecord
{
public List<ItemEquipGradeExpRecord> records = [];
}
public class UserExpRecord
{ {
public int level; public int level;
public int exp; public int exp;
public int reward_id; public int reward_id;
} }
public class UserExpTable
{
public List<UserExpRecord> records = [];
}
public class CharacterCostumeRecord [MemoryPackable]
public partial class CharacterCostumeRecord
{ {
public int id; public int id;
} }
public class CharacterCostumeTable
{
public List<CharacterCostumeRecord> records = [];
}
public class SideStoryStageRecord [MemoryPackable]
public partial class SideStoryStageRecord
{ {
public int id; public int id;
public int first_clear_reward; public int first_clear_reward;
} }
public class SideStoryStageTable
{
public List<SideStoryStageRecord> records = [];
}
public class TriggerRecord [MemoryPackable]
public partial class TriggerRecord
{ {
public int id; public int id;
public int condition_id; public int condition_id;
@@ -694,15 +675,13 @@
public bool print_value; public bool print_value;
public int before_trigger_id; public int before_trigger_id;
} }
public class TriggerTable
{
public List<TriggerRecord> records = [];
}
public class InfracoreFunction public class InfracoreFunction
{ {
public int function; public int function;
} }
public class InfracoreRecord [MemoryPackable]
public partial class InfracoreRecord
{ {
public int id; public int id;
public int grade; public int grade;
@@ -710,22 +689,16 @@
public int infra_core_exp; public int infra_core_exp;
public List<InfracoreFunction> function_list = []; public List<InfracoreFunction> function_list = [];
} }
public class InfracoreTable [MemoryPackable]
{ public partial class AttractiveCounselCharacterRecord
public List<InfracoreRecord> records = [];
}
public class AttractiveCounselCharacterRecord
{ {
public int id; public int id;
public int name_code; public int name_code;
public int collect_reward_id; public int collect_reward_id;
} }
public class AttractiveCounselCharacterTable
{
public List<AttractiveCounselCharacterRecord> records = [];
}
public class AttractiveLevelRewardRecord [MemoryPackable]
public partial class AttractiveLevelRewardRecord
{ {
public int id; public int id;
public int name_code; public int name_code;
@@ -733,11 +706,8 @@
public int attractive_level; public int attractive_level;
public int costume; public int costume;
} }
public class AttractiveLevelRewardTable [MemoryPackable]
{ public partial class SubquestRecord
public List<AttractiveLevelRewardRecord> records = [];
}
public class SubquestRecord
{ {
public int id; public int id;
public int group_id; public int group_id;
@@ -747,11 +717,9 @@
public string end_messenger_conversation_id = ""; public string end_messenger_conversation_id = "";
public int before_sub_quest_id; public int before_sub_quest_id;
} }
public class SubquestTable
{ [MemoryPackable]
public List<SubquestRecord> records = []; public partial class MessengerDialogRecord
}
public class MessengerDialogRecord
{ {
public string id = ""; public string id = "";
public string conversation_id = ""; public string conversation_id = "";
@@ -759,41 +727,36 @@
public bool is_opener; public bool is_opener;
public int reward_id; public int reward_id;
} }
public class MessengerDialogTable [MemoryPackable]
{ public partial class MessengerMsgConditionRecord
public List<MessengerDialogRecord> records = [];
}
public class MessengerMsgConditionRecord
{ {
public int id; public int id;
public string tid = ""; public string tid = "";
public int reward_id; public int reward_id;
} }
public class MessengerMsgConditionTable public enum ScenarioRewardCondition
{ {
public List<MessengerMsgConditionRecord> records = []; MainScenario,
} AttractiveScenario
public class ScenarioRewardRecord
{
public int id;
public string condition_id = "";
public string condition_type = "";
public int reward_id;
}
public class ScenarioRewardTable
{
public List<ScenarioRewardRecord> records = [];
} }
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 int id;
} }
public class ProductOfferTable
{ [MemoryPackable]
public List<ProductOfferRecord> records = []; public partial class InterceptionRecord
}
public class InterceptionRecord
{ {
public int id; public int id;
public int group; public int group;
@@ -801,11 +764,9 @@
public int percent_condition_reward_group; public int percent_condition_reward_group;
public long fixed_damage; public long fixed_damage;
} }
public class InterceptionTable
{ [MemoryPackable]
public List<InterceptionRecord> records = []; public partial class ConditionRewardRecord
}
public class ConditionRewardRecord
{ {
public int id; public int id;
public int group; public int group;
@@ -814,10 +775,7 @@
public long value_max; public long value_max;
public int reward_id; public int reward_id;
} }
public class ConditionRewardTable
{
public List<ConditionRewardRecord> records = [];
}
public enum ItemSubType public enum ItemSubType
{ {
BundleBox, BundleBox,
@@ -829,7 +787,8 @@
ArcadeItem, ArcadeItem,
EquipCombination EquipCombination
} }
public class ItemConsumeRecord [MemoryPackable]
public partial class ItemConsumeRecord
{ {
public int id; public int id;
public string use_type = ""; public string use_type = "";
@@ -838,22 +797,18 @@
public int use_id; public int use_id;
public int use_value; public int use_value;
} }
public class ItemConsumeTable
{ [MemoryPackable]
public List<ItemConsumeRecord> records = []; public partial class ItemPieceRecord
}
public class ItemPieceRecord
{ {
public int id; public int id;
public string use_type = ""; public string use_type = "";
public int use_id; public int use_id;
public int use_value; public int use_value;
} }
public class ItemPieceTable
{ [MemoryPackable]
public List<ItemPieceRecord> records = []; public partial class RandomItemRecord
}
public class RandomItemRecord
{ {
public int id; public int id;
public int group_id; public int group_id;
@@ -863,11 +818,9 @@
public int reward_value_max; public int reward_value_max;
public int ratio; public int ratio;
} }
public class RandomItemTable
{ [MemoryPackable]
public List<RandomItemRecord> records = []; public partial class RecycleResearchStatRecord
}
public class RecycleResearchStatRecord
{ {
public int id; public int id;
public string recycle_type = ""; public string recycle_type = "";
@@ -877,11 +830,9 @@
public int defense; public int defense;
public int hp; public int hp;
} }
public class RecycleResearchStatTable
{ [MemoryPackable]
public List<RecycleResearchStatRecord> records = []; public partial class RecycleResearchLevelRecord
}
public class RecycleResearchLevelRecord
{ {
public int id; public int id;
public string recycle_type = ""; public string recycle_type = "";
@@ -890,16 +841,15 @@
public int item_id; public int item_id;
public int item_value; public int item_value;
} }
public class RecycleResearchLevelTable
{
public List<RecycleResearchLevelRecord> records = [];
}
public enum ContentOpenType public enum ContentOpenType
{ {
Stage, Stage,
NonUpdate NonUpdate
} }
public class LostSectorRecord
[MemoryPackable]
public partial class LostSectorRecord
{ {
public int id; public int id;
public int sector; public int sector;
@@ -910,20 +860,14 @@
public int open_condition_value; public int open_condition_value;
} }
public class LostSectorTable [MemoryPackable]
{ public partial class LostSectorStageRecord
public List<LostSectorRecord> records = [];
}
public class LostSectorStageRecord
{ {
public int id; public int id;
public bool is_use_quick_battle; public bool is_use_quick_battle;
public int sector; public int sector;
} }
public class LostSectorStageTable
{
public List<LostSectorStageRecord> records = [];
}
public class ItemSpawner public class ItemSpawner
{ {
@@ -936,14 +880,13 @@
public string positionId = ""; public string positionId = "";
public int stageId; public int stageId;
} }
public class MapInfo
[MemoryPackable]
public partial class MapInfo
{ {
public string id { get; set; } = ""; public string id { get; set; } = "";
public List<ItemSpawner> ItemSpawner { get; set; } = []; public List<ItemSpawner> ItemSpawner { get; set; } = [];
public List<StageSpawner> StageSpawner { get; set; } = []; public List<StageSpawner> StageSpawner { get; set; } = [];
} }
public class MapInfoTable
{
public List<MapInfo> records = [];
}
} }

View File

@@ -2,10 +2,9 @@ namespace EpinelPS.Data
{ {
[System.AttributeUsage(System.AttributeTargets.Field)] [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 File { get; set; } = file;
public string PrimaryKey { get; set; } = primaryKey; public string PrimaryKey { get; set; } = primaryKey;
public Type TableType { get; set; } = tableType;
} }
} }

View File

@@ -27,6 +27,7 @@
<PackageReference Include="Google.Api.CommonProtos" Version="2.17.0" /> <PackageReference Include="Google.Api.CommonProtos" Version="2.17.0" />
<PackageReference Include="Google.Protobuf.Tools" Version="3.31.1" /> <PackageReference Include="Google.Protobuf.Tools" Version="3.31.1" />
<PackageReference Include="Grpc.AspNetCore" Version="2.71.0" /> <PackageReference Include="Grpc.AspNetCore" Version="2.71.0" />
<PackageReference Include="MemoryPack" Version="1.21.4" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" /> <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Paseto.Core" Version="1.4.1" /> <PackageReference Include="Paseto.Core" Version="1.4.1" />

View File

@@ -31,7 +31,7 @@ namespace EpinelPS.LobbyServer.Stage
var response = new ResClearStage(); var response = new ResClearStage();
var clearedStage = GameData.Instance.GetStageData(StageId) ?? throw new Exception("cleared stage cannot be null"); 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) 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) if (StageId > user.LastHardStageCleared)
user.LastHardStageCleared = StageId; user.LastHardStageCleared = StageId;
} }
else if (clearedStage.chapter_mod == "Normal") else
{ {
if (StageId > user.LastNormalStageCleared) if (StageId > user.LastNormalStageCleared)
user.LastNormalStageCleared = StageId; 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 else
{ {
Console.WriteLine("Unknown stage category " + clearedStage.stage_category); 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 // add outpost reward level if unlocked
if (user.MainQuestData.TryGetValue(21, out bool _)) if (user.MainQuestData.TryGetValue(21, out bool _))
@@ -137,9 +133,9 @@ namespace EpinelPS.LobbyServer.Stage
// Mark chapter as completed if boss stage was completed // 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); user.AddTrigger(TriggerType.HardChapterClear, 1, clearedStage.chapter_id);
else else
user.AddTrigger(TriggerType.ChapterClear, 1, clearedStage.chapter_id); user.AddTrigger(TriggerType.ChapterClear, 1, clearedStage.chapter_id);

View File

@@ -15,9 +15,9 @@ namespace EpinelPS.LobbyServer.Stage
var response = new ResEnterStage(); var response = new ResEnterStage();
var clearedStage = GameData.Instance.GetStageData(req.StageId) ?? throw new Exception("cleared stage cannot be null"); 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 // When entering a boss stage, unlock boss information in campaign
if (!user.FieldInfoNew.ContainsKey(map)) if (!user.FieldInfoNew.ContainsKey(map))

View File

@@ -12,7 +12,7 @@ namespace EpinelPS.LobbyServer.Stage
ReqGetStageData req = await ReadData<ReqGetStageData>(); ReqGetStageData req = await ReadData<ReqGetStageData>();
var user = GetUser(); 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() ResGetStageData response = new()
{ {