Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report wrong upgrades to an API #368

Merged
merged 19 commits into from
Oct 26, 2023
3 changes: 3 additions & 0 deletions ElectronicObserver/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using ElectronicObserver.Database;
using ElectronicObserver.Services;
using ElectronicObserver.Utility;
using ElectronicObserver.Utility.ElectronicObserverApi;
using ElectronicObserver.ViewModels.Translations;
using ElectronicObserver.Window.Control.ShipFilter;
using ElectronicObserver.Window.Dialog.EquipmentPicker;
Expand Down Expand Up @@ -289,6 +290,7 @@ private void ConfigureServices()
.AddSingleton<AlbumMasterEquipmentUpgradeTranslationViewModel>()
.AddSingleton<SortieDetailTranslationViewModel>()
.AddSingleton<TelegramTranslationViewModel>()
.AddSingleton<ElectronicObserverApiTranslationViewModel>()
// tools
.AddSingleton<ShipPickerViewModel>()
.AddSingleton<AutoRefreshViewModel>()
Expand All @@ -305,6 +307,7 @@ private void ConfigureServices()
.AddSingleton<EquipmentUpgradePlanManager>()
.AddSingleton<TimeChangeService>()
.AddSingleton<ColorService>()
.AddSingleton<ElectronicObserverApiService>()
// external
.AddSingleton(JotTracker())

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.IO;
using ElectronicObserver.Utility;
using ElectronicObserver.Utility.ElectronicObserverApi.DataIssueLogs;

namespace ElectronicObserver.Data.Translation;

Expand Down Expand Up @@ -27,9 +28,13 @@ public class DataAndTranslationManager
public FitBonusData FitBonus { get; private set; }
public EquipmentUpgradeData EquipmentUpgrade { get; private set; }

public DataAndTranslationIssueReporter DataAndTranslationIssueReporter { get; }

public DataAndTranslationManager()
{
Initialize();

DataAndTranslationIssueReporter = new();
}

public void Initialize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -756,4 +756,10 @@ When enabled, the preview will be ignored and all compositions will be shown.</v
<data name="Language_Korean" xml:space="preserve">
<value>Korean</value>
</data>
<data name="Debug_ElectronicObserverApiUrl" xml:space="preserve">
<value>Electronic Observer API URL</value>
</data>
<data name="Debug_ElectronicObserverApiUrlToolTip" xml:space="preserve">
<value>URL for the Electronic Observer API used to repport data issues.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -774,4 +774,10 @@ APIリストの書式や用法はオンラインヘルプを参照してくだ
<data name="Language_Korean" xml:space="preserve">
<value>韓国語</value>
</data>
<data name="Debug_ElectronicObserverApiUrl" xml:space="preserve">
<value>七四式EN API URL</value>
</data>
<data name="Debug_ElectronicObserverApiUrlToolTip" xml:space="preserve">
<value>データ問題を報告するために使用される七四式EN APIのURL</value>
</data>
</root>
5 changes: 5 additions & 0 deletions ElectronicObserver/Utility/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,11 @@ public class ConfigDebug : ConfigPartBase
/// </summary>
public string APIListPath { get; set; }

/// <summary>
/// Electronic Observer API URL
/// </summary>
public string ElectronicObserverApiUrl { get; set; } = "";

/// <summary>
/// エラー発生時に警告音を鳴らすか
/// </summary>
Expand Down
17 changes: 17 additions & 0 deletions ElectronicObserver/Utility/Data/EquipmentUpgradeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ElectronicObserverTypes;
using ElectronicObserverTypes.Serialization.EquipmentUpgrade;

namespace ElectronicObserver.Utility.Data;
public static class EquipmentUpgradeExtensions
{
public static List<EquipmentUpgradeDataModel> CanUpgradeEquipments(this IShipDataMaster ship, DayOfWeek day, List<EquipmentUpgradeDataModel> upgradesData)
=> upgradesData.Where(upgrade => upgrade.Improvement
.Any(improvement => improvement.Helpers
.Any(helpers => helpers.ShipIds.Contains(ship.ShipID) && helpers.CanHelpOnDays.Contains(day))
)
)
.ToList();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using ElectronicObserver.Observer;

namespace ElectronicObserver.Utility.ElectronicObserverApi.DataIssueLogs;

public class DataAndTranslationIssueReporter
{
private WrongUpgradesIssueReporter WrongUpgradesIssueReporter { get; }

public DataAndTranslationIssueReporter()
{
WrongUpgradesIssueReporter = new();

SubscribeToAPI();
}

private void SubscribeToAPI()
{
APIObserver api = APIObserver.Instance;

api.ApiReqKousyou_RemodelSlotList.ResponseReceived += WrongUpgradesIssueReporter.ProcessUpgradeList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace ElectronicObserver.Utility.ElectronicObserverApi.DataIssueLogs;

public record EquipmentUpgradeIssueModel
{
[JsonPropertyName("software_version")] public string SoftwareVersion { get; set; } = "";

[JsonPropertyName("data_version")] public int DataVersion { get; set; }

[JsonPropertyName("expected")] public List<int> ExpectedUpgrades { get; set; } = new();

[JsonPropertyName("actual")] public List<int> ActualUpgrades { get; set; } = new();

[JsonPropertyName("day")] public DayOfWeek Day { get; set; }

[JsonPropertyName("helperId")] public int HelperId { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using CommunityToolkit.Mvvm.DependencyInjection;
using ElectronicObserver.Data;
using ElectronicObserver.KancolleApi.Types.ApiReqKousyou.RemodelSlotlist;
using ElectronicObserver.Utility.Data;
using ElectronicObserver.Utility.Mathematics;
using ElectronicObserverTypes;
using ElectronicObserverTypes.Serialization.EquipmentUpgrade;

namespace ElectronicObserver.Utility.ElectronicObserverApi.DataIssueLogs;

public class WrongUpgradesIssueReporter
{
public void ProcessUpgradeList(string _, dynamic data)
{
ElectronicObserverApiService api = Ioc.Default.GetRequiredService<ElectronicObserverApiService>();

// if no helper => ignore
int helperId = KCDatabase.Instance.Fleet.Fleets[1].Members[1];
if (helperId <= 0) return;
IShipData helper = KCDatabase.Instance.Ships[helperId];

List<APIReqKousyouRemodelSlotlistResponse>? parsedResponse = ParseResponse(data);

List<EquipmentUpgradeDataModel> expectedUpgrades = EquipmentsThatCanBeUpgradedByCurrentHelper(helper.MasterShip);

if (CheckForIssue(parsedResponse, expectedUpgrades))
{
EquipmentUpgradeIssueModel report = new()
{
DataVersion = SoftwareUpdater.CurrentVersion.EquipmentUpgrades,
ActualUpgrades = parsedResponse.Select(apiData => apiData.ApiSlotId).ToList(),
ExpectedUpgrades = expectedUpgrades.Select(upgrade => upgrade.EquipmentId).ToList(),
Day = DateTimeHelper.GetJapanStandardTimeNow().DayOfWeek,
SoftwareVersion = SoftwareInformation.VersionEnglish,
HelperId = (int)helper.MasterShip.ShipId
};

#pragma warning disable CS4014
api.PostJson("EquipmentUpgradeIssues", report);
#pragma warning restore CS4014
}
}

/// <summary>
/// Checks for issues
/// </summary>
/// <returns>true if an issue is detected</returns>
private bool CheckForIssue(List<APIReqKousyouRemodelSlotlistResponse> actualUpgrades, List<EquipmentUpgradeDataModel> expectedUpgrades)
{
// Check data
if (actualUpgrades.Any(actualUpgrade => expectedUpgrades.All(upgSaved => upgSaved.EquipmentId != actualUpgrade.ApiSlotId) && !IsBaseUpgradeEquipment((EquipmentId)actualUpgrade.ApiSlotId)))
{
return true;
}

return expectedUpgrades.Any(expectedUpgrade => actualUpgrades.All(upgApi => expectedUpgrade.EquipmentId != upgApi.ApiSlotId));
}

private List<APIReqKousyouRemodelSlotlistResponse>? ParseResponse(dynamic data)
{
if (!data.IsArray) return null;

return JsonSerializer.Deserialize<List<APIReqKousyouRemodelSlotlistResponse>>(data.ToString());
}

private List<EquipmentUpgradeDataModel> EquipmentsThatCanBeUpgradedByCurrentHelper(IShipDataMaster helper)
{
KCDatabase db = KCDatabase.Instance;

return helper.CanUpgradeEquipments(DateTimeHelper.GetJapanStandardTimeNow().DayOfWeek,
db.Translation.EquipmentUpgrade.UpgradeList)
.ToList();
}

private bool IsBaseUpgradeEquipment(EquipmentId equipmentId) => equipmentId is
EquipmentId.MainGunSmall_12_7cmTwinGun or
EquipmentId.MainGunMedium_14cmSingleGun or
EquipmentId.Torpedo_61cmQuadrupleTorpedo or
EquipmentId.DepthCharge_Type94DepthChargeProjector;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema

Version 2.0

The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.

Example:

... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>

There are any number of "resheader" rows that contain simple
name/value pairs.

Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.

The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:

Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.

mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ElectronicObserverApi" xml:space="preserve">
<value>Electronic Observer API</value>
</data>
</root>
Loading