diff --git a/ElectronicObserver.Core/Types/CsvDateConverter.cs b/ElectronicObserver.Core/Types/CsvDateConverter.cs new file mode 100644 index 000000000..52a0bde08 --- /dev/null +++ b/ElectronicObserver.Core/Types/CsvDateConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Core.Types; + +public class CsvDateConverter : JsonConverter +{ + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string? raw = reader.GetString(); + + if (raw is null) return new(); + + return DateTimeHelper.CSVStringToTime(raw); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); + } +} diff --git a/ElectronicObserver.Core/Types/CsvNullableDateConverter.cs b/ElectronicObserver.Core/Types/CsvNullableDateConverter.cs new file mode 100644 index 000000000..1d73087c5 --- /dev/null +++ b/ElectronicObserver.Core/Types/CsvNullableDateConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Core.Types; + +public class CsvNullableDateConverter : JsonConverter +{ + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string? raw = reader.GetString(); + + if (raw is null) return null; + + return DateTimeHelper.CSVStringToTime(raw); + } + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + { + writer.WriteStringValue(value?.ToString("yyyy-MM-dd HH:mm:ss")); + } +} diff --git a/ElectronicObserver.Core/Types/Extensions/QuestIdentifierExtensions.cs b/ElectronicObserver.Core/Types/Extensions/QuestIdentifierExtensions.cs deleted file mode 100644 index 7430f1b11..000000000 --- a/ElectronicObserver.Core/Types/Extensions/QuestIdentifierExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Core.Types.Quests; -using ElectronicObserver.Core.Types.Serialization.Quests; - -namespace ElectronicObserver.Core.Types.Extensions; - -public static class QuestIdentifierExtensions -{ - public static bool ProgressResetsDaily(this IQuestIdentifier questData, List questsMetadata) - { - // Dailies - if (questData.QuestResetType is QuestResetType.Daily) return true; - - return questData.QuestID switch - { - // Quests that are not daily but only appear on some days : - 211 => true, // 空母3 - 212 => true, // 輸送5 - - // Some PVP quests - 311 => true, - 330 => true, - 337 => true, - 339 => true, - 341 => true, - 342 => true, - 348 => true, - - // Special cases - _ => questsMetadata.Find(quest => quest.ApiId == questData.QuestID)?.QuestProgressResetType is QuestProgressResetType.Daily, - }; - } -} diff --git a/ElectronicObserver.Core/Types/MaintenanceState.cs b/ElectronicObserver.Core/Types/MaintenanceState.cs new file mode 100644 index 000000000..d5a0b5532 --- /dev/null +++ b/ElectronicObserver.Core/Types/MaintenanceState.cs @@ -0,0 +1,9 @@ +namespace ElectronicObserver.Core.Types; + +public enum MaintenanceState +{ + None = 0, + EventStart = 1, + EventEnd = 2, + Regular = 3 +}; diff --git a/ElectronicObserver.Core/Types/Quests/IQuestIdentifier.cs b/ElectronicObserver.Core/Types/Quests/IQuestIdentifier.cs deleted file mode 100644 index d2a11555b..000000000 --- a/ElectronicObserver.Core/Types/Quests/IQuestIdentifier.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ElectronicObserver.Core.Types.Quests; - -public interface IQuestIdentifier -{ - public int QuestID { get; } - public QuestResetType QuestResetType { get; } -} diff --git a/ElectronicObserver.Core/Types/Quests/QuestProgressResetType.cs b/ElectronicObserver.Core/Types/Quests/QuestProgressResetType.cs deleted file mode 100644 index 58c0ac928..000000000 --- a/ElectronicObserver.Core/Types/Quests/QuestProgressResetType.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ElectronicObserver.Core.Types.Quests; - -public enum QuestProgressResetType -{ - Unknown = 0, - Daily = 1, -} diff --git a/ElectronicObserver.Core/Types/Serialization/Quests/QuestMetadata.cs b/ElectronicObserver.Core/Types/Serialization/Quests/QuestMetadata.cs index 939a65a1f..fc31f641f 100644 --- a/ElectronicObserver.Core/Types/Serialization/Quests/QuestMetadata.cs +++ b/ElectronicObserver.Core/Types/Serialization/Quests/QuestMetadata.cs @@ -13,5 +13,5 @@ public record QuestMetadata public DateTime? EndTime { get; set; } [JsonPropertyName("resetType")] - public QuestProgressResetType? QuestProgressResetType { get; set; } + public QuestResetType? QuestProgressResetType { get; set; } } diff --git a/ElectronicObserver.Core/Types/SoftwareUpdateData.cs b/ElectronicObserver.Core/Types/SoftwareUpdateData.cs new file mode 100644 index 000000000..0476bfdef --- /dev/null +++ b/ElectronicObserver.Core/Types/SoftwareUpdateData.cs @@ -0,0 +1,52 @@ +using System; +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Core.Types; + +public class SoftwareUpdateData +{ + [JsonPropertyName("bld_date")] + [JsonConverter(typeof(CsvDateConverter))] + public DateTime BuildDate { get; set; } + + [JsonPropertyName("ver")] + public string AppVersion { get; set; } = "0.0.0.0"; + + [JsonPropertyName("url")] + public string AppDownloadUrl { get; set; } = ""; + + [JsonPropertyName("ApiServer")] + public string AppApiServerUrl { get; set; } = ""; + + [JsonPropertyName("nodes")] + public int Destination { get; set; } + + [JsonPropertyName("QuestTrackers")] + public int QuestTrackers { get; set; } + + [JsonPropertyName("QuestsMetadata")] + public int QuestsMetadata { get; set; } + + [JsonPropertyName("Locks")] + public int EventLocks { get; set; } + + [JsonPropertyName("FitBonuses")] + public int FitBonuses { get; set; } + + [JsonPropertyName("EquipmentUpgrades")] + public int EquipmentUpgrades { get; set; } + + [JsonPropertyName("MaintStart")] + [JsonConverter(typeof(CsvDateConverter))] + public DateTime MaintenanceStart { get; set; } + + [JsonPropertyName("MaintEnd")] + [JsonConverter(typeof(CsvNullableDateConverter))] + public DateTime? MaintenanceEnd { get; set; } + + [JsonPropertyName("MaintInfoLink")] + public string MaintenanceInformationLink { get; set; } = ""; + + [JsonPropertyName("MaintEventState")] + public MaintenanceState EventState { get; set; } +} diff --git a/ElectronicObserver.Core/Types/TranslationUpdateData.cs b/ElectronicObserver.Core/Types/TranslationUpdateData.cs new file mode 100644 index 000000000..a960f5e80 --- /dev/null +++ b/ElectronicObserver.Core/Types/TranslationUpdateData.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Core.Types; + +public class TranslationUpdateData +{ + [JsonPropertyName("equipment")] + public string Equipment { get; set; } = ""; + + [JsonPropertyName("expedition")] + public string Expedition { get; set; } = ""; + + [JsonPropertyName("operation")] + public string Operation { get; set; } = ""; + + [JsonPropertyName("quest")] + public string Quest { get; set; } = ""; + + [JsonPropertyName("ship")] + public string Ship { get; set; } = ""; + + [JsonPropertyName("Locks")] + public int LockTranslations { get; set; } +} diff --git a/ElectronicObserver/Data/Quest/ProgressData.cs b/ElectronicObserver/Data/Quest/ProgressData.cs index bc3e22ad6..5cc734412 100644 --- a/ElectronicObserver/Data/Quest/ProgressData.cs +++ b/ElectronicObserver/Data/Quest/ProgressData.cs @@ -9,7 +9,7 @@ namespace ElectronicObserver.Data.Quest; /// 任務の進捗を管理する基底クラスです。 /// [DataContract(Name = "ProgressData")] -public abstract class ProgressData : IIdentifiable, IQuestIdentifier +public abstract class ProgressData : IIdentifiable { /// @@ -198,6 +198,14 @@ public virtual void ApplyTemporaryProgress(QuestData q) } } + public QuestResetType GetProgressResetType() => TryGetQuest()?.GetProgressResetType() ?? QuestResetType.Unknown; + + private QuestData? TryGetQuest() + { + if (!KCDatabase.Instance.Quest.Quests.ContainsKey(QuestID)) return null; + + return KCDatabase.Instance.Quest[QuestID]; + } /// /// この任務の達成に必要な条件を表す文字列を返します。 diff --git a/ElectronicObserver/Data/QuestData.cs b/ElectronicObserver/Data/QuestData.cs index 88d7c63d4..9e44eee58 100644 --- a/ElectronicObserver/Data/QuestData.cs +++ b/ElectronicObserver/Data/QuestData.cs @@ -1,12 +1,15 @@ -using ElectronicObserver.Core.Types.Data; +using System; +using System.Collections.Generic; +using ElectronicObserver.Core.Types.Data; using ElectronicObserver.Core.Types.Quests; +using ElectronicObserver.Core.Types.Serialization.Quests; namespace ElectronicObserver.Data; /// /// 任務のデータを保持します。 /// -public class QuestData : ResponseWrapper, IIdentifiable, IQuestIdentifier +public class QuestData : ResponseWrapper, IIdentifiable { /// @@ -25,8 +28,6 @@ public class QuestData : ResponseWrapper, IIdentifiable, IQuestIdentifier /// public int Type => (int)RawData.api_type; - public QuestResetType QuestResetType => (QuestResetType)Type; - /// /// 周期アイコン種別 /// 1=単発, 2=デイリー, 3=ウィークリー, 6=マンスリー, 7=他(輸送5と空母3,クォータリー), 100+x=イヤーリー(x月-) @@ -88,7 +89,66 @@ public int State /// public int Progress => (int)RawData.api_progress_flag; + public QuestResetType GetProgressResetType() + { + Dictionary questsMetadata = KCDatabase.Instance.Translation.QuestsMetadata.QuestsMetadataList; + + if (questsMetadata.TryGetValue(QuestID, out QuestMetadata? metadata) && metadata.QuestProgressResetType is { } resetType) + { + return resetType; + } + + return Type switch + { + 1 => QuestResetType.Daily, + 2 => QuestResetType.Weekly, + 3 => QuestResetType.Monthly, + 4 => QuestResetType.Never, + 5 => LabelType switch + { + // 2, 3, 6 should never happen + 2 => QuestResetType.Daily, + 3 => QuestResetType.Weekly, + 6 => QuestResetType.Monthly, + 7 => ID switch + { + // BD4 - 3 carriers + 211 => QuestResetType.Daily, + // BD6 - 5 transports + 212 => QuestResetType.Daily, + + // this will be incorrect if they add any new odd daily quests + _ => QuestResetType.Quarterly + }, + 101 => QuestResetType.January, + 102 => QuestResetType.February, + 103 => QuestResetType.March, + 104 => QuestResetType.April, + 105 => QuestResetType.May, + 106 => QuestResetType.June, + 107 => QuestResetType.July, + 108 => QuestResetType.August, + 109 => QuestResetType.September, + 110 => QuestResetType.October, + 111 => QuestResetType.November, + 112 => QuestResetType.December, + + _ => QuestResetType.Unknown + }, + + _ => QuestResetType.Unknown + }; + } + + public DateTime? GetEndDateTime() + { + if (KCDatabase.Instance.Translation.QuestsMetadata.QuestsMetadataList.TryGetValue(QuestID, out QuestMetadata? metadata) && metadata.EndTime is { } endTime) + { + return endTime - TimeSpan.FromHours(9) + TimeZoneInfo.Local.BaseUtcOffset; + } + return null; + } public int ID => QuestID; public override string ToString() => $"[{QuestID}] {Name}"; diff --git a/ElectronicObserver/Data/QuestManager.cs b/ElectronicObserver/Data/QuestManager.cs index 8648c5521..f153b16d1 100644 --- a/ElectronicObserver/Data/QuestManager.cs +++ b/ElectronicObserver/Data/QuestManager.cs @@ -3,6 +3,7 @@ using ElectronicObserver.Core; using ElectronicObserver.Core.Types.Data; using ElectronicObserver.Core.Types.Extensions; +using ElectronicObserver.Core.Types.Quests; namespace ElectronicObserver.Data; @@ -56,7 +57,7 @@ public override void LoadFromResponse(string apiname, dynamic data) //周期任務削除 if (DateTimeHelper.IsCrossedDay(progress.LastUpdateTime, 5, 0, 0)) { - progress.Progresses.RemoveAll(p => p.ProgressResetsDaily(KCDatabase.Instance.Translation.QuestsMetadata.QuestsMetadataList)); + progress.Progresses.RemoveAll(p => p.GetProgressResetType() is QuestResetType.Daily); Quests.RemoveAll(q => q.Type == 1 || q.QuestID == 211 /* 空母3 */ || q.QuestID == 212 /* 輸送5 */ || q.QuestID == 311 /* 演習勝利7 */ ); } if (DateTimeHelper.IsCrossedWeek(progress.LastUpdateTime, DayOfWeek.Monday, 5, 0, 0)) diff --git a/ElectronicObserver/Data/Translation/QuestsMetadata.cs b/ElectronicObserver/Data/Translation/QuestsMetadata.cs index 1297a8edd..218226897 100644 --- a/ElectronicObserver/Data/Translation/QuestsMetadata.cs +++ b/ElectronicObserver/Data/Translation/QuestsMetadata.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using ElectronicObserver.Core.Types.Serialization.Quests; namespace ElectronicObserver.Data.Translation; @@ -8,7 +9,7 @@ public class QuestsMetadata : TranslationBase { private string QuestMetadataPath => Path.Join(DataAndTranslationManager.DataFolder, "QuestsMetadata.json"); - public List QuestsMetadataList { get; private set; } = []; + public Dictionary QuestsMetadataList { get; private set; } = []; public sealed override void Initialize() { @@ -25,6 +26,10 @@ private void LoadDictionary(string path) QuestsMetadataList.Clear(); List? json = Load>(path); - if (json != null) QuestsMetadataList = json; + + if (json is { } list) + { + QuestsMetadataList = list.ToDictionary(item => item.ApiId, item => item); + } } } diff --git a/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/FitBonusIssueReporter.cs b/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/FitBonusIssueReporter.cs index 8286d45e7..591f21d6e 100644 --- a/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/FitBonusIssueReporter.cs +++ b/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/FitBonusIssueReporter.cs @@ -72,7 +72,7 @@ private void ReportIssue(IShipData ship, FitBonusValue theoricalBonus, FitBonusV { FitBonusIssueModel issue = new FitBonusIssueModel() { - DataVersion = SoftwareUpdater.CurrentVersion.FitBonuses, + DataVersion = SoftwareUpdater.CurrentDataVersion.FitBonuses, SoftwareVersion = SoftwareInformation.VersionEnglish, SoftwareDataSource = Configuration.Config.Control.UpdateRepoURL.ToString(), diff --git a/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesCostIssueReporter.cs b/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesCostIssueReporter.cs index 522a41d26..cd8f24259 100644 --- a/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesCostIssueReporter.cs +++ b/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesCostIssueReporter.cs @@ -104,7 +104,7 @@ public void ProcessUpgradeCostResponse(string _, dynamic data) return new() { SoftwareVersion = SoftwareInformation.VersionEnglish, - DataVersion = SoftwareUpdater.CurrentVersion.EquipmentUpgrades, + DataVersion = SoftwareUpdater.CurrentDataVersion.EquipmentUpgrades, SoftwareDataSource = Configuration.Config.Control.UpdateRepoURL.ToString(), EquipmentId = Equipment.EquipmentId, diff --git a/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesIssueReporter.cs b/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesIssueReporter.cs index b3670e100..c616b3051 100644 --- a/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesIssueReporter.cs +++ b/ElectronicObserver/Utility/ElectronicObserverApi/DataIssueLogs/WrongUpgradesIssueReporter.cs @@ -34,7 +34,7 @@ public void ProcessUpgradeList(string _, dynamic data) { EquipmentUpgradeIssueModel report = new() { - DataVersion = SoftwareUpdater.CurrentVersion.EquipmentUpgrades, + DataVersion = SoftwareUpdater.CurrentDataVersion.EquipmentUpgrades, SoftwareVersion = SoftwareInformation.VersionEnglish, SoftwareDataSource = Configuration.Config.Control.UpdateRepoURL.ToString(), diff --git a/ElectronicObserver/Utility/ElectronicObserverApi/ElectronicObserverApiService.cs b/ElectronicObserver/Utility/ElectronicObserverApi/ElectronicObserverApiService.cs index cc1d155ac..653b94501 100644 --- a/ElectronicObserver/Utility/ElectronicObserverApi/ElectronicObserverApiService.cs +++ b/ElectronicObserver/Utility/ElectronicObserverApi/ElectronicObserverApiService.cs @@ -19,7 +19,7 @@ public class ElectronicObserverApiService(ElectronicObserverApiTranslationViewMo private string Url => Configuration.Config.Debug.ElectronicObserverApiUrl switch { { Length: >0 } => Configuration.Config.Debug.ElectronicObserverApiUrl, - _ => SoftwareUpdater.CurrentVersion.AppApiServerUrl, + _ => SoftwareUpdater.CurrentDataVersion.AppApiServerUrl, }; private ElectronicObserverApiTranslationViewModel Translations { get; } = translations; diff --git a/ElectronicObserver/Utility/SoftwareUpdater.cs b/ElectronicObserver/Utility/SoftwareUpdater.cs index 0f79d0c84..26d54e401 100644 --- a/ElectronicObserver/Utility/SoftwareUpdater.cs +++ b/ElectronicObserver/Utility/SoftwareUpdater.cs @@ -2,15 +2,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Net; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using DynaJson; -using ElectronicObserver.Core; +using ElectronicObserver.Core.Types; using ElectronicObserver.Data; using ElectronicObserver.Data.Translation; -using ElectronicObserver.Utility.Mathematics; using ElectronicObserver.ViewModels.Translations; namespace ElectronicObserver.Utility; @@ -21,8 +19,12 @@ public class SoftwareUpdater Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "ElectronicObserver"); private static bool WaitForRestart { get; set; } - public static UpdateData CurrentVersion { get; set; } = new UpdateData(); - public static UpdateData LatestVersion { get; set; } = new UpdateData(); + + public static SoftwareUpdateData CurrentDataVersion { get; set; } = new(); + public static SoftwareUpdateData LatestDataVersion { get; set; } = new(); + + public static TranslationUpdateData CurrentTranslationVersion { get; set; } = new(); + public static TranslationUpdateData LatestTranslationVersion { get; set; } = new(); private static Uri DataUpdateURL => new($"{Configuration.Config.Control.UpdateRepoURL}/update.json"); @@ -46,7 +48,7 @@ public static async Task UpdateSoftware() if (!Directory.Exists(AppDataFolder)) Directory.CreateDirectory(AppDataFolder); - var url = LatestVersion.AppDownloadUrl; + var url = LatestDataVersion.AppDownloadUrl; if (url != string.Empty) { try @@ -109,12 +111,6 @@ public static async Task CheckUpdateAsync() { await ReadRemoteAndLocalUpdateData(); - /*if (Configuration.Config.Life.CheckUpdateInformation == true && SoftwareInformation.UpdateTime < LatestVersion.BuildDate) - { - FormMain.Instance.Update_Available(LatestVersion.AppVersion); - UpdateSoftware(); - }*/ - List<(string FileName, DataType Type)> downloadList = GetDownloadList(); bool needReload = downloadList.Count > 0; @@ -140,15 +136,8 @@ public static async Task CheckUpdateAsync() Logger.Add(2, SoftwareInformationResources.TranslationFilesUpdated); } - CurrentVersion = LatestVersion; - } - catch (JsonParserException e) - { - // file exist but isn't valid json - // file gets corrupted somehow? - File.Delete(TranslationUpdateFile); - File.Delete(DataUpdateFile); - await CheckUpdateAsync(); + CurrentDataVersion = LatestDataVersion; + CurrentTranslationVersion = LatestTranslationVersion; } catch (Exception e) { @@ -160,50 +149,50 @@ public static async Task CheckUpdateAsync() { List<(string FileName, DataType Type)> downloadList = []; - if (CurrentVersion.Equipment != LatestVersion.Equipment) + if (CurrentTranslationVersion.Equipment != LatestTranslationVersion.Equipment) downloadList.Add(("equipment.json", DataType.Translation)); - if (CurrentVersion.Expedition != LatestVersion.Expedition) + if (CurrentTranslationVersion.Expedition != LatestTranslationVersion.Expedition) downloadList.Add(("expedition.json", DataType.Translation)); - if (CurrentVersion.Destination != LatestVersion.Destination) + if (CurrentDataVersion.Destination != LatestDataVersion.Destination) downloadList.Add((("destination.json", DataType.Data))); - if (CurrentVersion.Operation != LatestVersion.Operation) + if (CurrentTranslationVersion.Operation != LatestTranslationVersion.Operation) downloadList.Add(("operation.json", DataType.Translation)); - if (CurrentVersion.Quest != LatestVersion.Quest) + if (CurrentTranslationVersion.Quest != LatestTranslationVersion.Quest) downloadList.Add(("quest.json", DataType.Translation)); - if (CurrentVersion.Ship != LatestVersion.Ship) + if (CurrentTranslationVersion.Ship != LatestTranslationVersion.Ship) downloadList.Add(("ship.json", DataType.Translation)); - if (CurrentVersion.QuestTrackers < LatestVersion.QuestTrackers) + if (CurrentDataVersion.QuestTrackers < LatestDataVersion.QuestTrackers) { downloadList.Add(("QuestTrackers.json", DataType.Data)); } - if (CurrentVersion.TimeLimitedQuest < LatestVersion.TimeLimitedQuest) + if (CurrentDataVersion.QuestsMetadata < LatestDataVersion.QuestsMetadata) { - downloadList.Add(("TimeLimitedQuests.json", DataType.Data)); + downloadList.Add(("QuestsMetadata.json", DataType.Data)); } - if (CurrentVersion.EventLocks < LatestVersion.EventLocks) + if (CurrentDataVersion.EventLocks < LatestDataVersion.EventLocks) { downloadList.Add(("Locks.json", DataType.Data)); } - if (CurrentVersion.LockTranslations < LatestVersion.LockTranslations) + if (CurrentTranslationVersion.LockTranslations < LatestTranslationVersion.LockTranslations) { downloadList.Add(("Locks.json", DataType.Translation)); } - if (CurrentVersion.FitBonuses < LatestVersion.FitBonuses) + if (CurrentDataVersion.FitBonuses < LatestDataVersion.FitBonuses) { downloadList.Add(("FitBonuses.json", DataType.Data)); } - if (CurrentVersion.EquipmentUpgrades < LatestVersion.EquipmentUpgrades) + if (CurrentDataVersion.EquipmentUpgrades < LatestDataVersion.EquipmentUpgrades) { downloadList.Add(("EquipmentUpgrades.json", DataType.Data)); } @@ -228,10 +217,7 @@ private static async Task ReadRemoteAndLocalUpdateData() if (updateDataReceived) { - var jsonData = JsonObject.Parse(dataUpdateData); - var jsonTranslations = JsonObject.Parse(translationUpdateData); - - LatestVersion = ParseUpdate(jsonData, jsonTranslations); + (LatestDataVersion, LatestTranslationVersion) = ParseUpdate(dataUpdateData, translationUpdateData); } bool filesDoesntExist = !File.Exists(DataUpdateFile) || !File.Exists(TranslationUpdateFile); @@ -241,13 +227,14 @@ private static async Task ReadRemoteAndLocalUpdateData() await File.WriteAllTextAsync(DataUpdateFile, dataUpdateData); await File.WriteAllTextAsync(TranslationUpdateFile, translationUpdateData); - CurrentVersion = new UpdateData(); + CurrentDataVersion = new(); + CurrentTranslationVersion = new(); } else { string dataFileContent = File.ReadAllText(DataUpdateFile); string translationFileContent = File.ReadAllText(TranslationUpdateFile); - CurrentVersion = ParseUpdate(JsonObject.Parse(dataFileContent), JsonObject.Parse(translationFileContent)); + (CurrentDataVersion, CurrentTranslationVersion) = ParseUpdate(dataFileContent, translationFileContent); } } @@ -256,7 +243,7 @@ private static async Task DownloadUpdater() try { using HttpClient client = new(); - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + var url = @"https://raw.githubusercontent.com/ElectronicObserverEN/Data/master/Data/EOUpdater.exe"; var updaterFile = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + @"\EOUpdater.exe"; @@ -285,7 +272,7 @@ private static async Task DownloadUpdate(string url) { using HttpClient client = new(); string tempFile = AppDataFolder + @"\latest.zip"; ; - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + Console.WriteLine(SoftwareInformationResources.DownloadingUpdate); Progress progress = new(); @@ -305,97 +292,27 @@ private static async Task DownloadUpdate(string url) } } - internal static UpdateData ParseUpdate(dynamic dataJson, dynamic translationJson) + private static (SoftwareUpdateData, TranslationUpdateData) ParseUpdate(string dataJson, string translationJson) { - var data = new UpdateData(); try { - DateTime buildDate = DateTimeHelper.CSVStringToTime(dataJson.bld_date); - var appVersion = (string)dataJson.ver; - var downloadUrl = (string)dataJson.url; - - string apiServerUrl = dataJson.ApiServer() switch - { - true => (string)dataJson.ApiServer, - _ => "", - }; - - var eqVersion = (string)translationJson.equipment; - var expedVersion = (string)translationJson.expedition; - string destVersion = dataJson.nodes.ToString(); - var opVersion = (string)translationJson.operation; - var questVersion = (string)translationJson.quest; - var shipVersion = (string)translationJson.ship; - int lockTranslationsVersion = (int)translationJson.Locks; - - int fitBonusesVersion = dataJson.FitBonuses() switch - { - true => (int)dataJson.FitBonuses, - _ => 0, - }; + SoftwareUpdateData? data = JsonSerializer.Deserialize(dataJson); + TranslationUpdateData? translations = JsonSerializer.Deserialize(translationJson); - int questTrackersVersion = dataJson.QuestTrackers() switch + if (data is not null && translations is not null) { - true => (int)dataJson.QuestTrackers, - _ => 0, - }; - - int timeLimitedQuestsVersion = dataJson.TimeLimitedQuest() switch - { - true => (int)dataJson.TimeLimitedQuest, - _ => 0, - }; - - int eventLocksVersion = (int)dataJson.Locks; - - int equipmentUpgradesVersion = dataJson.EquipmentUpgrades() switch - { - true => (int)dataJson.EquipmentUpgrades, - _ => 0, - }; - - DateTime maintenanceStartDate = DateTimeHelper.CSVStringToTime(dataJson.MaintStart); - - DateTime? maintenanceEndDate = dataJson.MaintEnd switch - { - null => null, - _ => DateTimeHelper.CSVStringToTime(dataJson.MaintEnd), - }; - - var eventState = (MaintenanceState)(int)dataJson.MaintEventState; - string maintenanceInformationLink = (string)dataJson.MaintInfoLink; - - data = new UpdateData - { - BuildDate = buildDate, - AppVersion = appVersion, - AppDownloadUrl = downloadUrl, - AppApiServerUrl = apiServerUrl, - Equipment = eqVersion, - Expedition = expedVersion, - Destination = destVersion, - Operation = opVersion, - Quest = questVersion, - Ship = shipVersion, - QuestTrackers = questTrackersVersion, - TimeLimitedQuest = timeLimitedQuestsVersion, - EventLocks = eventLocksVersion, - LockTranslations = lockTranslationsVersion, - MaintenanceStart = maintenanceStartDate, - MaintenanceEnd = maintenanceEndDate, - EventState = eventState, - FitBonuses = fitBonusesVersion, - EquipmentUpgrades = equipmentUpgradesVersion, - MaintenanceInformationLink = maintenanceInformationLink - }; + return (data, translations); + } } catch (Exception e) { Logger.Add(3, SoftwareInformationResources.FailedToParseUpdateData + e.ToString()); } - return data; - } + return (new(), new()); + } + + private static string GetFullPath(string fileName, DataType type) => type switch { DataType.Translation => Path.Combine("Translations", DataAndTranslationManager.CurrentTranslationLanguage, fileName), @@ -431,32 +348,3 @@ public static async Task DownloadData(string filename, DataType type) } } } - -public class UpdateData -{ - public DateTime BuildDate { get; set; } - public string AppVersion { get; set; } = "0.0.0.0"; - public string AppDownloadUrl { get; set; } = ""; - public string AppApiServerUrl { get; set; } = ""; - public string Equipment { get; set; } = ""; - public string Expedition { get; set; } = ""; - public string Destination { get; set; } = ""; - public string Operation { get; set; } = ""; - public string Quest { get; set; } = ""; - public string Ship { get; set; } = ""; - public int QuestTrackers { get; set; } - public int TimeLimitedQuest { get; set; } - public int EventLocks { get; set; } - public int LockTranslations { get; set; } - public int FitBonuses { get; set; } - public int EquipmentUpgrades { get; set; } - public DateTime MaintenanceStart { get; set; } - public DateTime? MaintenanceEnd { get; set; } - public string MaintenanceInformationLink { get; set; } = ""; - - /// - /// 1=event start, 2=event end, 3=regular maintenance - /// - public MaintenanceState EventState { get; set; } -} -public enum MaintenanceState { None = 0, EventStart = 1, EventEnd = 2, Regular = 3 }; diff --git a/ElectronicObserver/ViewModels/FormMainViewModel.cs b/ElectronicObserver/ViewModels/FormMainViewModel.cs index 929f303bd..034940b80 100644 --- a/ElectronicObserver/ViewModels/FormMainViewModel.cs +++ b/ElectronicObserver/ViewModels/FormMainViewModel.cs @@ -1665,7 +1665,7 @@ private void OpenReleaseNotes() #region Maintenance timer [RelayCommand] private void OpenMaintenanceInformationLink() - => OpenLink(SoftwareUpdater.LatestVersion.MaintenanceInformationLink); + => OpenLink(SoftwareUpdater.LatestDataVersion.MaintenanceInformationLink); #endregion private void CallPumpkinHead(string apiname, dynamic data) @@ -1770,7 +1770,7 @@ private void UIUpdateTimer_Tick(object sender, EventArgs e) DateTime now = DateTimeHelper.GetJapanStandardTimeNow(); MaintenanceText = GetMaintenanceText(FormMain, now); - UpdateAvailable = SoftwareInformation.UpdateTime < SoftwareUpdater.LatestVersion.BuildDate; + UpdateAvailable = SoftwareInformation.UpdateTime < SoftwareUpdater.LatestDataVersion.BuildDate; DownloadProgressString = SoftwareUpdater.DownloadProgressString; @@ -1858,10 +1858,10 @@ private void UIUpdateTimer_Tick(object sender, EventArgs e) private static string GetMaintenanceText(FormMainTranslationViewModel formMain, DateTime now) { TimeSpan maintTimer = new(0); - MaintenanceState eventState = SoftwareUpdater.LatestVersion.EventState; + MaintenanceState eventState = SoftwareUpdater.LatestDataVersion.EventState; - DateTime maintStartDate = SoftwareUpdater.LatestVersion.MaintenanceStart; - DateTime? maintEndDate = SoftwareUpdater.LatestVersion.MaintenanceEnd; + DateTime maintStartDate = SoftwareUpdater.LatestDataVersion.MaintenanceStart; + DateTime? maintEndDate = SoftwareUpdater.LatestDataVersion.MaintenanceEnd; if (eventState != MaintenanceState.None) { diff --git a/ElectronicObserver/ViewModels/Translations/FormQuestTranslationViewModel.cs b/ElectronicObserver/ViewModels/Translations/FormQuestTranslationViewModel.cs index 33b6bcb14..dca063cda 100644 --- a/ElectronicObserver/ViewModels/Translations/FormQuestTranslationViewModel.cs +++ b/ElectronicObserver/ViewModels/Translations/FormQuestTranslationViewModel.cs @@ -9,6 +9,7 @@ public class FormQuestTranslationViewModel : TranslationBaseViewModel public string QuestView_Name => GeneralRes.QuestName.Replace("_", "__").Replace("&", "_"); public string QuestView_Progress => GeneralRes.Progress.Replace("_", "__").Replace("&", "_"); public string QuestView_ProgressResetsDaily => GeneralRes.ProgressResetsDaily; + public string QuestView_EndsOn => GeneralRes.QuestEndsOn; public string MenuMain_QuestFilter => QuestResources.MenuMain_QuestFilter.Replace("_", "__").Replace("&", "_"); public string ShowInProgressOnly => GeneralRes.ShowInProgressOnly.Replace("_", "__").Replace("&", "_"); diff --git a/ElectronicObserver/Window/Dialog/QuestTrackerManager/Models/QuestModel.cs b/ElectronicObserver/Window/Dialog/QuestTrackerManager/Models/QuestModel.cs index 76c01b8f4..6bc1a1f91 100644 --- a/ElectronicObserver/Window/Dialog/QuestTrackerManager/Models/QuestModel.cs +++ b/ElectronicObserver/Window/Dialog/QuestTrackerManager/Models/QuestModel.cs @@ -14,46 +14,7 @@ public record QuestModel([property: Key(0)] int Id) [IgnoreMember] public QuestCategory Category => (QuestCategory)(TryGetQuest()?.Category ?? 0); [IgnoreMember] public int State => TryGetQuest()?.State ?? 0; [IgnoreMember] - public QuestResetType ResetType => TryGetQuest()?.Type switch - { - 1 => QuestResetType.Daily, - 2 => QuestResetType.Weekly, - 3 => QuestResetType.Monthly, - 4 => QuestResetType.Never, - 5 => TryGetQuest()?.LabelType switch - { - // 2, 3, 6 should never happen - 2 => QuestResetType.Daily, - 3 => QuestResetType.Weekly, - 6 => QuestResetType.Monthly, - 7 => TryGetQuest()?.ID switch - { - // BD4 - 3 carriers - 211 => QuestResetType.Daily, - // BD6 - 5 transports - 212 => QuestResetType.Daily, - - // this will be incorrect if they add any new odd daily quests - _ => QuestResetType.Quarterly - }, - 101 => QuestResetType.January, - 102 => QuestResetType.February, - 103 => QuestResetType.March, - 104 => QuestResetType.April, - 105 => QuestResetType.May, - 106 => QuestResetType.June, - 107 => QuestResetType.July, - 108 => QuestResetType.August, - 109 => QuestResetType.September, - 110 => QuestResetType.October, - 111 => QuestResetType.November, - 112 => QuestResetType.December, - - _ => QuestResetType.Unknown - }, - - _ => QuestResetType.Unknown - }; + public QuestResetType ResetType => TryGetQuest()?.GetProgressResetType() ?? QuestResetType.Unknown; [IgnoreMember] public string Display => $"{Code}: {Name} (ID: {Id})"; diff --git a/ElectronicObserver/Window/GeneralRes.en.resx b/ElectronicObserver/Window/GeneralRes.en.resx index f806bcd30..197f677a1 100644 --- a/ElectronicObserver/Window/GeneralRes.en.resx +++ b/ElectronicObserver/Window/GeneralRes.en.resx @@ -851,4 +851,10 @@ Please click here to restart. Progress resets daily + + Ends on {0} + + + Quests that end on {0} + \ No newline at end of file diff --git a/ElectronicObserver/Window/GeneralRes.resx b/ElectronicObserver/Window/GeneralRes.resx index 6b10fa094..ccb137989 100644 --- a/ElectronicObserver/Window/GeneralRes.resx +++ b/ElectronicObserver/Window/GeneralRes.resx @@ -850,4 +850,10 @@ デイリーリセット + + {0}で終わる + + + {0}で終わるクエスト + \ No newline at end of file diff --git a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs index cc3fdb710..d1c9c630b 100644 --- a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs +++ b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; @@ -46,6 +47,7 @@ public InformationViewModel() : base("Info", "Information", IconContent.FormInfo o.ApiReqMap_Next.ResponseReceived += Updated; o.ApiReqPractice_Battle.ResponseReceived += Updated; o.ApiGetMember_SortieConditions.ResponseReceived += Updated; + o.ApiGetMember_QuestList.ResponseReceived += (_, _) => QuestListUpdated(); o.ApiReqMission_Start.RequestReceived += Updated; Utility.Configuration.Instance.ConfigurationChanged += ConfigurationChanged; @@ -162,6 +164,30 @@ private void Updated(string apiname, dynamic data) } } + + private void QuestListUpdated() + { + StringBuilder info = new(); + KCDatabase db = KCDatabase.Instance; + + IEnumerable> questListByEndDate = db.Quest.Quests.Values + .OrderBy(q => q.ID) + .Where(q => q.GetEndDateTime() is not null) + .GroupBy(q => (DateTime)q.GetEndDateTime()!); + + foreach (IGrouping questByEndDate in questListByEndDate) + { + info.AppendLine(string.Format(GeneralRes.QuestListEndsOn, questByEndDate.Key)); + + foreach (QuestData quest in questByEndDate) + { + info.AppendLine($"{quest.Code}: {quest.Name}"); + } + } + + Text = info.ToString(); + } + private string GetPracticeEnemyInfo(dynamic data) { StringBuilder sb = new(); diff --git a/ElectronicObserver/Window/Wpf/Quest/QuestViewModel.cs b/ElectronicObserver/Window/Wpf/Quest/QuestViewModel.cs index e3b66b722..3b02b17d4 100644 --- a/ElectronicObserver/Window/Wpf/Quest/QuestViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Quest/QuestViewModel.cs @@ -13,6 +13,8 @@ using DynaJson; using ElectronicObserver.Core.Services; using ElectronicObserver.Core.Types.Extensions; +using ElectronicObserver.Core.Types.Quests; +using ElectronicObserver.Core.Types.Serialization.Quests; using ElectronicObserver.Data; using ElectronicObserver.Data.Quest; using ElectronicObserver.Resource; @@ -418,10 +420,21 @@ private void Updated() row.QuestView_NameToolTip += $"\r\n{tracker?.GroupConditions.Display}"; } - if (q.Type != 1 && q.ProgressResetsDaily(KCDatabase.Instance.Translation.QuestsMetadata.QuestsMetadataList)) + row.QuestView_NameToolTipExtra = ""; + + if (q.Type != 1 && q.GetProgressResetType() is QuestResetType.Daily) + { + row.QuestView_NameToolTipExtra += $"{FormQuest.QuestView_ProgressResetsDaily}"; + } + + if (q.GetEndDateTime() is DateTime endTime) + { + row.QuestView_NameToolTipExtra += string.Format(FormQuest.QuestView_EndsOn, endTime); + } + + if (row.QuestView_NameToolTipExtra?.Length > 0) { row.QuestView_NameToolTip += "\r\n"; - row.QuestView_NameToolTipExtra = $"{FormQuest.QuestView_ProgressResetsDaily}"; } } {