Skip to content

Commit

Permalink
Improved source generators (#268)
Browse files Browse the repository at this point in the history
* initial draft for improved source gen

* add tests for new generator and restructure generator project

* keep ordering of data container properties in generated code

* add data element analyzer and unittests, refactor data element generator

* add new DataContainer attribute to data containers to enable new generator

* update PropertyChangedSourceGenerator to use FAWMN

* code cleanup for generators and analyzer

* add TextKind type to better specify how a type should be treated

* move data elements to reduce unnecessary namespace nesting

* fix unittests after moving data elements to new namespace

* fix tests for PropertyChangedGenerator

* fix sonarlint warnings and issues from review
  • Loading branch information
floribe2000 authored Oct 14, 2023
1 parent aa083c9 commit 5311fe7
Show file tree
Hide file tree
Showing 88 changed files with 4,640 additions and 2,038 deletions.
11 changes: 5 additions & 6 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggesti
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_qualification_for_event = false:suggestion
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_event = true:suggestion
dotnet_style_qualification_for_field = true:suggestion
dotnet_style_qualification_for_method = true:suggestion
dotnet_style_qualification_for_property = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion

# ReSharper properties
Expand Down Expand Up @@ -112,9 +112,8 @@ dotnet_diagnostic.rs2008.severity = none # Ignore analyzer release tracking
dotnet_diagnostic.sa0001.severity = none # Ignore disabled xml documentation
dotnet_diagnostic.sa1000.severity = none # Ignore missing space after "new"
dotnet_diagnostic.sa1009.severity = none # Ignore missing space after closing parenthesis
dotnet_diagnostic.sa1028.severity = none # Ignore trailing whitespace
dotnet_diagnostic.sa1100.severity = none # Ignore base. prefix if there is no local override
dotnet_diagnostic.sa1101.severity = none # Ignore missing this prefix for local calls
dotnet_diagnostic.sa1101.severity = suggestion # Ignore missing this prefix for local calls
dotnet_diagnostic.sa1122.severity = none # Don't force the use of string.Empty
dotnet_diagnostic.sa1124.severity = none # Allow the use of regions
dotnet_diagnostic.sa1127.severity = none # Generic constraints may share a line with other declarations
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using WoWsShipBuilder.DataElements;
using WoWsShipBuilder.DataElements.DataElementAttributes;
using WoWsShipBuilder.DataElements.DataElements;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.DataStructures.Ship;
using WoWsShipBuilder.Infrastructure.ApplicationData;
using WoWsShipBuilder.Infrastructure.Utility;

namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record AirstrikeDataContainer : DataContainerBase
{
public string Header { get; set; } = default!;

[DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true)]
[DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)]
public string Name { get; set; } = default!;

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "HP")]
Expand Down
608 changes: 304 additions & 304 deletions WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using WoWsShipBuilder.DataElements;
using WoWsShipBuilder.DataElements.DataElementAttributes;
using WoWsShipBuilder.DataElements.DataElements;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.DataStructures.Ship;
using WoWsShipBuilder.Infrastructure.Utility;

namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record DepthChargesLauncherDataContainer : DataContainerBase
{
[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Globalization;
using System.Text;
using WoWsShipBuilder.DataElements;
using WoWsShipBuilder.DataElements.DataElementAttributes;
using WoWsShipBuilder.DataElements.DataElements;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.DataStructures.Ship;
using WoWsShipBuilder.Infrastructure.GameData;
Expand All @@ -10,9 +10,10 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record MainBatteryDataContainer : DataContainerBase
{
[DataElementType(DataElementTypes.FormattedText, ValuesPropertyName = "TurretNames", ArePropertyNameValuesKeys = true)]
[DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "TurretNames", ArgumentsTextKind = TextKind.LocalizationKey)]
public string Name { get; set; } = default!;

public List<string> TurretNames { get; set; } = new();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,103 +1,103 @@
using Microsoft.Extensions.Logging;
using WoWsShipBuilder.DataElements;
using WoWsShipBuilder.DataElements.DataElementAttributes;
using WoWsShipBuilder.DataElements.DataElements;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.DataStructures.Ship;
using WoWsShipBuilder.Infrastructure.Utility;

namespace WoWsShipBuilder.DataContainers
namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record PingerGunDataContainer : DataContainerBase
{
public partial record PingerGunDataContainer : DataContainerBase
{
[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")]
public decimal Reload { get; set; }
[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")]
public decimal Reload { get; set; }

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "DegreePerSecond")]
public decimal TraverseSpeed { get; set; }

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "DegreePerSecond")]
public decimal TraverseSpeed { get; set; }
[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")]
public decimal TurnTime { get; set; }

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")]
public decimal TurnTime { get; set; }
[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")]
public decimal Range { get; set; }

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")]
public decimal Range { get; set; }
[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "PingDuration", UnitKey = "S", LocalizationKeyOverride = "First")]
public decimal FirstPingDuration { get; set; }

[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "PingDuration", UnitKey = "S", NameLocalizationKey = "First")]
public decimal FirstPingDuration { get; set; }
[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "PingDuration", UnitKey = "S", LocalizationKeyOverride = "Second")]
public decimal SecondPingDuration { get; set; }

[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "PingDuration", UnitKey = "S", NameLocalizationKey = "Second")]
public decimal SecondPingDuration { get; set; }
[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "M")]
public decimal PingWidth { get; set; }

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "M")]
public decimal PingWidth { get; set; }
[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MPS")]
public decimal PingSpeed { get; set; }

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MPS")]
public decimal PingSpeed { get; set; }
public static PingerGunDataContainer? FromShip(Ship ship, IEnumerable<ShipUpgrade> shipConfiguration, List<(string name, float value)> modifiers)
{
if (!ship.PingerGunList.Any())
{
return null;
}

public static PingerGunDataContainer? FromShip(Ship ship, IEnumerable<ShipUpgrade> shipConfiguration, List<(string name, float value)> modifiers)
PingerGun pingerGun;
var pingerUpgrade = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Sonar);
if (pingerUpgrade is null && ship.PingerGunList.Count is 1)
{
if (!ship.PingerGunList.Any())
{
return null;
}

PingerGun pingerGun;
var pingerUpgrade = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Sonar);
if (pingerUpgrade is null && ship.PingerGunList.Count is 1)
{
Logging.Logger.LogWarning("No sonar upgrade information found for ship {ShipName} even though there is one sonar module available", ship.Name);
return null;
}

if (pingerUpgrade is null)
{
throw new InvalidOperationException($"No sonar upgrade information found for ship {ship.Name} but there is more than one sonar module.");
}

// Safe approach is necessary because data up until 0.11.9#1 does not include this data due to an issue in the data converter
if (pingerUpgrade.Components.TryGetValue(ComponentType.Sonar, out string[]? pingerGunInfo))
{
pingerGun = ship.PingerGunList[pingerGunInfo.First()];
}
else
{
Logging.Logger.LogWarning("Unable to retrieve sonar component from upgrade info for ship {} and ship upgrade {}", ship.Index, pingerUpgrade.Name);
pingerGun = ship.PingerGunList.First().Value;
}

var pingSpeed = pingerGun.WaveParams.First().WaveSpeed.First();
var pingSpeedModifiers = modifiers.FindModifiers("pingerWaveSpeedCoeff");
pingSpeed = pingSpeedModifiers.Aggregate(pingSpeed, (current, pingSpeedModifier) => current * (decimal)pingSpeedModifier);

var firstPingDuration = pingerGun.SectorParams[0].Lifetime;
var firstPingDurationModifiers = modifiers.FindModifiers("firstSectorTimeCoeff");
firstPingDuration = firstPingDurationModifiers.Aggregate(firstPingDuration, (current, firstPingDurationModifier) => current * (decimal)firstPingDurationModifier);

var secondPingDuration = pingerGun.SectorParams[1].Lifetime;
var secondPingDurationModifiers = modifiers.FindModifiers("secondSectorTimeCoeff");
secondPingDuration = secondPingDurationModifiers.Aggregate(secondPingDuration, (current, secondPingDurationModifiersModifier) => current * (decimal)secondPingDurationModifiersModifier);

var traverseSpeed = pingerGun.RotationSpeed[0];

var arModifiers = modifiers.FindModifiers("lastChanceReloadCoefficient");
var reload = arModifiers.Aggregate(pingerGun.WaveReloadTime, (current, arModifier) => current * (1 - ((decimal)arModifier / 100)));
var pingReloadModifiers = modifiers.FindModifiers("pingerReloadCoeff");
reload = pingReloadModifiers.Aggregate(reload, (current, pingReloadModifier) => current * (decimal)pingReloadModifier);

var pingerGunDataContainer = new PingerGunDataContainer
{
TurnTime = Math.Round(180 / traverseSpeed, 1),
TraverseSpeed = traverseSpeed,
Reload = Math.Round(reload, 2),
Range = pingerGun.WaveDistance / 1000,
FirstPingDuration = Math.Round(firstPingDuration, 1),
SecondPingDuration = Math.Round(secondPingDuration, 1),
PingWidth = pingerGun.WaveParams.First().StartWaveWidth,
PingSpeed = Math.Round(pingSpeed, 0),
};

pingerGunDataContainer.UpdateDataElements();

return pingerGunDataContainer;
Logging.Logger.LogWarning("No sonar upgrade information found for ship {ShipName} even though there is one sonar module available", ship.Name);
return null;
}

if (pingerUpgrade is null)
{
throw new InvalidOperationException($"No sonar upgrade information found for ship {ship.Name} but there is more than one sonar module.");
}

// Safe approach is necessary because data up until 0.11.9#1 does not include this data due to an issue in the data converter
if (pingerUpgrade.Components.TryGetValue(ComponentType.Sonar, out string[]? pingerGunInfo))
{
pingerGun = ship.PingerGunList[pingerGunInfo.First()];
}
else
{
Logging.Logger.LogWarning("Unable to retrieve sonar component from upgrade info for ship {} and ship upgrade {}", ship.Index, pingerUpgrade.Name);
pingerGun = ship.PingerGunList.First().Value;
}

var pingSpeed = pingerGun.WaveParams.First().WaveSpeed.First();
var pingSpeedModifiers = modifiers.FindModifiers("pingerWaveSpeedCoeff");
pingSpeed = pingSpeedModifiers.Aggregate(pingSpeed, (current, pingSpeedModifier) => current * (decimal)pingSpeedModifier);

var firstPingDuration = pingerGun.SectorParams[0].Lifetime;
var firstPingDurationModifiers = modifiers.FindModifiers("firstSectorTimeCoeff");
firstPingDuration = firstPingDurationModifiers.Aggregate(firstPingDuration, (current, firstPingDurationModifier) => current * (decimal)firstPingDurationModifier);

var secondPingDuration = pingerGun.SectorParams[1].Lifetime;
var secondPingDurationModifiers = modifiers.FindModifiers("secondSectorTimeCoeff");
secondPingDuration = secondPingDurationModifiers.Aggregate(secondPingDuration, (current, secondPingDurationModifiersModifier) => current * (decimal)secondPingDurationModifiersModifier);

var traverseSpeed = pingerGun.RotationSpeed[0];

var arModifiers = modifiers.FindModifiers("lastChanceReloadCoefficient");
var reload = arModifiers.Aggregate(pingerGun.WaveReloadTime, (current, arModifier) => current * (1 - ((decimal)arModifier / 100)));
var pingReloadModifiers = modifiers.FindModifiers("pingerReloadCoeff");
reload = pingReloadModifiers.Aggregate(reload, (current, pingReloadModifier) => current * (decimal)pingReloadModifier);

var pingerGunDataContainer = new PingerGunDataContainer
{
TurnTime = Math.Round(180 / traverseSpeed, 1),
TraverseSpeed = traverseSpeed,
Reload = Math.Round(reload, 2),
Range = pingerGun.WaveDistance / 1000,
FirstPingDuration = Math.Round(firstPingDuration, 1),
SecondPingDuration = Math.Round(secondPingDuration, 1),
PingWidth = pingerGun.WaveParams.First().StartWaveWidth,
PingSpeed = Math.Round(pingSpeed, 0),
};

pingerGunDataContainer.UpdateDataElements();

return pingerGunDataContainer;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System.Globalization;
using Microsoft.Extensions.Logging;
using WoWsShipBuilder.DataElements;
using WoWsShipBuilder.DataElements.DataElementAttributes;
using WoWsShipBuilder.DataElements.DataElements;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.DataStructures.Ship;
using WoWsShipBuilder.Infrastructure.GameData;
using WoWsShipBuilder.Infrastructure.Utility;

namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record SecondaryBatteryDataContainer : DataContainerBase
{
public string Name { get; set; } = default!;
Expand Down Expand Up @@ -92,7 +93,7 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase
{
Name = arrangementString,
TurretName = turretName,
TurretSetup = new(arrangementString, turretName, AreValuesKeys: true),
TurretSetup = new(arrangementString, turretName, ArgumentsTextKind: DataElementTextKind.LocalizationKey),
BarrelsLayout = $"{secondaryGroup.Count} x {secondaryGun.NumBarrels}",
BarrelsCount = secondaryGroup.Count * secondaryGun.NumBarrels,
GunCaliber = Math.Round(secondaryGun.BarrelDiameter * 1000),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
using System.Globalization;
using System.Text;
using WoWsShipBuilder.DataElements;
using WoWsShipBuilder.DataElements.DataElementAttributes;
using WoWsShipBuilder.DataElements.DataElements;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.DataStructures.Ship;
using WoWsShipBuilder.Infrastructure.Utility;

namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record TorpedoArmamentDataContainer : DataContainerBase
{
[DataElementType(DataElementTypes.FormattedText, ValuesPropertyName = "LauncherNames", ArePropertyNameValuesKeys = true)]
[DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "LauncherNames", ArgumentsTextKind = TextKind.LocalizationKey)]
public string Name { get; set; } = default!;

public List<string> LauncherNames { get; set; } = new();
Expand Down Expand Up @@ -39,10 +40,10 @@ public partial record TorpedoArmamentDataContainer : DataContainerBase
[DataElementType(DataElementTypes.KeyValue)]
public string FullSalvoDamage { get; set; } = default!;

[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", NameLocalizationKey = "FirstOption")]
[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", LocalizationKeyOverride = "FirstOption")]
public string TorpFullSalvoDmg { get; set; } = default!;

[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", NameLocalizationKey = "SecondOption")]
[DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", LocalizationKeyOverride = "SecondOption")]
public string AltTorpFullSalvoDmg { get; set; } = default!;

public int LoadersCount { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record BombDataContainer : ProjectileDataContainer
{
[DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true, IsValueAppLocalization = true)]
[DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.AppLocalizationKey)]
public string BombType { get; set; } = default!;

[DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true)]
[DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)]
public string Name { get; set; } = default!;

[DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MM")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace WoWsShipBuilder.DataContainers;

[DataContainer]
public partial record DepthChargeDataContainer : ProjectileDataContainer
{
[DataElementType(DataElementTypes.KeyValue)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using WoWsShipBuilder.DataElements.DataElements;
using WoWsShipBuilder.DataElements;

namespace WoWsShipBuilder.DataContainers;

Expand Down
Loading

0 comments on commit 5311fe7

Please sign in to comment.