diff --git a/WotBlitzStatisticsPro.Common/Model/TankInfoHistoryResponse.cs b/WotBlitzStatisticsPro.Common/Model/TankInfoHistoryResponse.cs
new file mode 100644
index 0000000..d505dfc
--- /dev/null
+++ b/WotBlitzStatisticsPro.Common/Model/TankInfoHistoryResponse.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace WotBlitzStatisticsPro.Common.Model
+{
+ ///
+ /// Information about tank statistics history
+ ///
+ public class TankInfoHistoryResponse
+ {
+ ///
+ /// Player account identifier
+ ///
+ public long AccountId { get; set; }
+
+ ///
+ /// Tank identifier
+ ///
+ public long TankId { get; set; }
+
+ ///
+ /// Total time in battle until tank killed
+ ///
+ public int BattleLifeTimeInSeconds { get; set; }
+
+ ///
+ /// Last battle
+ ///
+ public DateTime LastBattleTime { get; set; } = new DateTime(1970, 1, 1);
+
+ ///
+ /// Mark of Mastery
+ ///
+ public MarkOfMastery MarkOfMastery { get; set; }
+
+
+ ///
+ /// Tank name
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// Is vehicle premium
+ ///
+ public bool IsPremium { get; set; }
+
+ ///
+ /// Vehicle type id
+ ///
+ public string? Type { get; set; }
+
+ ///
+ /// Vehicle nationId
+ ///
+ public string? Nation{ get; set; }
+
+ ///
+ /// Vehicle tier
+ ///
+ public int Tier { get; set; }
+
+ ///
+ /// Vehicle preview image
+ ///
+ public string? PreviewImage { get; set; }
+
+ ///
+ /// Vehicle normal image
+ ///
+ public string? NormalImage { get; set; }
+
+
+ ///
+ /// Overall statistics since tank was bought
+ ///
+ public ShortStatistics? OverallTankStatistics { get; set; }
+
+ ///
+ /// Statistics for period
+ ///
+ public ShortStatistics? TankPeriodStatistics { get; set; }
+
+ ///
+ /// Difference between start and end of the period
+ ///
+ public StatisticsDifference? PeriodDifference { get; set; }
+
+ ///
+ /// The detailed history
+ ///
+ public StatisticsDifference[]? StatisticsHistory { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.DataAccess/Model/Accounts/TankInfoHistory.cs b/WotBlitzStatisticsPro.DataAccess/Model/Accounts/TankInfoHistory.cs
index dd32160..3e0a715 100644
--- a/WotBlitzStatisticsPro.DataAccess/Model/Accounts/TankInfoHistory.cs
+++ b/WotBlitzStatisticsPro.DataAccess/Model/Accounts/TankInfoHistory.cs
@@ -1,9 +1,10 @@
using MongoDB.Bson.Serialization.Attributes;
+using WotBlitzStatisticsPro.Common.Model;
namespace WotBlitzStatisticsPro.DataAccess.Model.Accounts
{
- public class TankInfoHistory
- {
+ public class TankInfoHistory: IStatistics
+ {
public TankInfoHistory()
{
@@ -41,91 +42,100 @@ namespace WotBlitzStatisticsPro.DataAccess.Model.Accounts
///
/// Battles count
///
- public long Battles { get; set; }
+ public long? Battles { get; set; }
///
/// Base capture points
///
- public long CapturePoints { get; set; }
+ public long? CapturePoints { get; set; }
///
/// Damage dealt
///
- public long DamageDealt { get; set; }
+ public long? DamageDealt { get; set; }
///
/// Damage received
///
- public long DamageReceived { get; set; }
+ public long? DamageReceived { get; set; }
///
/// Base dropped capture points
///
- public long DroppedCapturePoints { get; set; }
+ public long? DroppedCapturePoints { get; set; }
///
/// Frags count
///
- public long Frags { get; set; }
+ public long? Frags { get; set; }
///
/// Frags count after 8 tier
///
- public long Frags8P { get; set; }
+ public long? Frags8P { get; set; }
///
/// Hits count
///
- public long Hits { get; set; }
+ public long? Hits { get; set; }
///
/// Losses count
///
- public long Losses { get; set; }
+ public long? Losses { get; set; }
///
/// Max frags per battle
///
- public long MaxFrags { get; set; }
+ public long? MaxFrags { get; set; }
///
/// Max XP per battle
///
- public long MaxXp { get; set; }
+ public long? MaxXp { get; set; }
///
/// Shots count
///
- public long Shots { get; set; }
+ public long? Shots { get; set; }
///
/// Spotted vehicles count
///
- public long Spotted { get; set; }
+ public long? Spotted { get; set; }
///
/// Amount of survived battles
///
- public long SurvivedBattles { get; set; }
+ public long? SurvivedBattles { get; set; }
///
/// Amount of survived and wined battles
///
- public long WinAndSurvived { get; set; }
+ public long? WinAndSurvived { get; set; }
///
/// Wins count
///
- public long Wins { get; set; }
+ public long? Wins { get; set; }
///
/// Total experience
///
- public long Xp { get; set; }
+ public long? Xp { get; set; }
///
/// Wn7 coefficient
///
public double Wn7 { get; set; }
+
+ #region redudant fields
+
+ public long? MaxFragsTankId { get; set; }
+ public long? MaxXpTankId { get; set; }
+ public double AvgTier { get; set; }
+
+ #endregion
+
}
}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.DataAccess/WargamingAccountDataAccessor.cs b/WotBlitzStatisticsPro.DataAccess/WargamingAccountDataAccessor.cs
index faf5695..28d40bf 100644
--- a/WotBlitzStatisticsPro.DataAccess/WargamingAccountDataAccessor.cs
+++ b/WotBlitzStatisticsPro.DataAccess/WargamingAccountDataAccessor.cs
@@ -125,7 +125,7 @@ namespace WotBlitzStatisticsPro.DataAccess
var history = await _database.GetCollection(TankInfoHistoryCollectionName)
.FindAsync(
Builders.Filter.Where(t =>
- t.TankInfoHistoryId.AccountId == accountId && t.TankId == tankId && t.TankInfoHistoryId.LastBattleTime >= lastBattleSince),
+ t.TankInfoHistoryId.AccountId == accountId && t.TankInfoHistoryId.TankId == tankId && t.TankInfoHistoryId.LastBattleTime >= lastBattleSince),
new FindOptions
{Sort = Builders.Sort.Descending(h => h.TankInfoHistoryId.LastBattleTime)});
return history.ToList();
diff --git a/WotBlitzStatisticsPro.GraphQl/Query/WotBlitzStatisticsQuery.cs b/WotBlitzStatisticsPro.GraphQl/Query/WotBlitzStatisticsQuery.cs
index 9679e42..76a9b2c 100644
--- a/WotBlitzStatisticsPro.GraphQl/Query/WotBlitzStatisticsQuery.cs
+++ b/WotBlitzStatisticsPro.GraphQl/Query/WotBlitzStatisticsQuery.cs
@@ -20,11 +20,6 @@ namespace WotBlitzStatisticsPro.GraphQl.Query
_wargamingAccounts = wargamingAccounts;
}
- //public Task GetPlayerInfo(long accountId)
- //{
- // return _wargamingSearcher.GetPlayerAccountInfo(accountId);
- //}
-
///
/// Finds Wargaming accounts by nick
///
@@ -87,5 +82,25 @@ namespace WotBlitzStatisticsPro.GraphQl.Query
return _wargamingAccounts.GetAccountInfoHistory(realmType ?? RealmType.Ru, accountId, startDate,
requestLanguage ?? RequestLanguage.En);
}
+
+ ///
+ /// Tank statistics history for period since "startDate"
+ ///
+ /// AccountId
+ /// TankId
+ /// Date from history started
+ /// Account region
+ /// Request language
+ ///
+ public Task TankInfoHistory(
+ long accountId,
+ long tankId,
+ DateTime startDate,
+ RealmType? realmType,
+ RequestLanguage? requestLanguage)
+ {
+ return _wargamingAccounts.GetTankInfoHistory(realmType ?? RealmType.Ru, accountId, tankId, startDate,
+ requestLanguage ?? RequestLanguage.En);
+ }
}
}
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/IDatabaseTankPipelineContextData.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/IDatabaseTankPipelineContextData.cs
new file mode 100644
index 0000000..4b7d87d
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/IDatabaseTankPipelineContextData.cs
@@ -0,0 +1,11 @@
+using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline
+{
+ public interface IDatabaseTankPipelineContextData
+ {
+ long TankId { get; }
+
+ TankInfo? DbTankInfo { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/FillTankHistoryResponseOperation.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/FillTankHistoryResponseOperation.cs
new file mode 100644
index 0000000..2dd58e9
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/FillTankHistoryResponseOperation.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.DataAccess;
+using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
+using WotBlitzStatisticsPro.Logic.Calculations;
+using WotBlitzStatisticsPro.Logic.Pipeline;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
+{
+ public class FillTankHistoryResponseOperation : IOperation
+ {
+ private readonly IDictionariesDataAccessor _wargamingDictionaries;
+
+ public FillTankHistoryResponseOperation(IDictionariesDataAccessor wargamingDictionaries)
+ {
+ _wargamingDictionaries = wargamingDictionaries;
+ }
+
+ public async Task Invoke(IOperationContext context, Func? next)
+ {
+ var contextData = context.Get();
+
+ if (contextData?.DbTankInfo == null)
+ {
+ if (next != null) await next.Invoke(context);
+ return;
+ }
+
+ var nations = await _wargamingDictionaries.GetNations(context.Request.RequestLanguage);
+ var tankTypes = await _wargamingDictionaries.GetTankTypes(context.Request.RequestLanguage);
+
+ var vehicleInfos = await _wargamingDictionaries.GetVehicles(new[] {contextData.TankId});
+ var vehicleInfo = vehicleInfos[contextData.TankId];
+
+ contextData.Response = new TankInfoHistoryResponse
+ {
+ TankId = contextData.TankId,
+ LastBattleTime = contextData.DbTankInfo.LastBattleTime.ToDateTime(),
+ BattleLifeTimeInSeconds = contextData.DbTankInfo.BattleLifeTimeInSeconds,
+ MarkOfMastery = contextData.DbTankInfo.MarkOfMastery,
+ Name = vehicleInfo.Name.FirstOrDefault(n => n.Language == context.Request.RequestLanguage)?.Value,
+ IsPremium = vehicleInfo.IsPremium,
+ Tier = vehicleInfo.Tier,
+ NormalImage = vehicleInfo.NormalImage,
+ PreviewImage = vehicleInfo.PreviewImage,
+ Nation = nations[vehicleInfo.NationId],
+ Type = tankTypes[vehicleInfo.TypeId],
+
+ AccountId = context.Request.AccountId,
+ PeriodDifference = contextData.PeriodDifference,
+ StatisticsHistory = contextData.StatisticsHistory,
+ TankPeriodStatistics = contextData.PeriodAccountStatistics,
+ OverallTankStatistics = contextData.OverallStatistics
+ };
+
+ if (next != null) await next.Invoke(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/ReadTankHistoryFromDbOperation.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/ReadTankHistoryFromDbOperation.cs
new file mode 100644
index 0000000..430e813
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/ReadTankHistoryFromDbOperation.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.DataAccess;
+using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
+using WotBlitzStatisticsPro.Logic.Calculations;
+using WotBlitzStatisticsPro.Logic.Pipeline;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
+{
+ public class ReadTankHistoryFromDbOperation : IOperation
+ {
+ private readonly IWargamingAccountDataAccessor _accountDataAccessor;
+
+ public ReadTankHistoryFromDbOperation(IWargamingAccountDataAccessor accountDataAccessor)
+ {
+ _accountDataAccessor = accountDataAccessor;
+ }
+
+ public async Task Invoke(IOperationContext context, Func? next)
+ {
+ var contextData = context.Get();
+
+ contextData.History = (await _accountDataAccessor.GetTankHistory(context.Request.AccountId, contextData.TankId, contextData.LastBattleSince.ToUnixTimestamp())).ToArray();
+ if (next != null) await next.Invoke(context);
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/ReadTankInfoFromDBOperation.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/ReadTankInfoFromDBOperation.cs
new file mode 100644
index 0000000..c13fb9f
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/ReadTankInfoFromDBOperation.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.DataAccess;
+using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
+using WotBlitzStatisticsPro.Logic.Pipeline;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
+{
+ public class ReadTankInfoFromDbOperation : IOperation
+ {
+ private readonly IWargamingAccountDataAccessor _accountDataAccessor;
+
+ public ReadTankInfoFromDbOperation(IWargamingAccountDataAccessor accountDataAccessor)
+ {
+ _accountDataAccessor = accountDataAccessor;
+ }
+
+ public async Task Invoke(IOperationContext context, Func? next)
+ {
+ var contextData = context.Get();
+
+ contextData.DbTankInfo = await _accountDataAccessor.ReadTankInfo(context.Request.AccountId, contextData.TankId);
+ if (next != null) await next.Invoke(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/TankHistoryInformationContextData.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/TankHistoryInformationContextData.cs
new file mode 100644
index 0000000..f9d0aec
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/TankHistoryInformationContextData.cs
@@ -0,0 +1,29 @@
+using System;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline
+{
+ public class TankHistoryInformationContextData: IDatabaseTankPipelineContextData, IStatisticsPipelineData
+ {
+ public TankHistoryInformationContextData(DateTime lastBattleSince, long tankId)
+ {
+ LastBattleSince = lastBattleSince;
+ TankId = tankId;
+ }
+
+ public DateTime LastBattleSince { get; }
+
+ public long TankId { get; }
+
+ public TankInfo? DbTankInfo { get; set; }
+
+ public IStatistics[]? History { get; set; }
+ public ShortStatistics? OverallStatistics { get; set; }
+ public ShortStatistics? PeriodAccountStatistics { get; set; }
+ public StatisticsDifference? PeriodDifference { get; set; }
+ public StatisticsDifference[]? StatisticsHistory { get; set; }
+
+ public TankInfoHistoryResponse? Response { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Calculations/TierHelper.cs b/WotBlitzStatisticsPro.Logic/Calculations/TierHelper.cs
index 6e169f4..6c4df1f 100644
--- a/WotBlitzStatisticsPro.Logic/Calculations/TierHelper.cs
+++ b/WotBlitzStatisticsPro.Logic/Calculations/TierHelper.cs
@@ -16,7 +16,7 @@ namespace WotBlitzStatisticsPro.Logic.Calculations
{
if (tankTires.ContainsKey(tank.TankId) && tank.Battles > 0)
{
- x += tankTires[tank.TankId] * tank.Battles;
+ x += tankTires[tank.TankId] * tank.Battles.DoubleValue();
}
}
if (account.Battles > 0)
diff --git a/WotBlitzStatisticsPro.Logic/Calculations/Wn7Helper.cs b/WotBlitzStatisticsPro.Logic/Calculations/Wn7Helper.cs
index 7a69aa2..87a9bf6 100644
--- a/WotBlitzStatisticsPro.Logic/Calculations/Wn7Helper.cs
+++ b/WotBlitzStatisticsPro.Logic/Calculations/Wn7Helper.cs
@@ -26,13 +26,18 @@ namespace WotBlitzStatisticsPro.Logic.Calculations
public static void CalculateWn7(this TankInfoHistory tank, double tier)
{
- double avdFrags = (double) tank.Frags / tank.Battles;
- double avgDamage = (double)tank.DamageDealt / tank.Battles;
- double avgSpot = (double)tank.Spotted / tank.Battles;
- double avgDef = (double)tank.DroppedCapturePoints / tank.Battles;
- double winRate = (100d * (double) tank.Wins / tank.Battles); // - 48;
+ if (!tank.Battles.HasValue)
+ {
+ return;
+ }
- tank.Wn7 = CalculateWn7(tank.Battles, tier, avdFrags, avgDamage, avgSpot, avgDef, winRate);
+ double avdFrags = (double) tank.Frags.DoubleValue() / tank.Battles.DoubleValue();
+ double avgDamage = (double)tank.DamageDealt.DoubleValue() / tank.Battles.DoubleValue();
+ double avgSpot = (double)tank.Spotted.DoubleValue() / tank.Battles.DoubleValue();
+ double avgDef = (double)tank.DroppedCapturePoints.DoubleValue() / tank.Battles.DoubleValue();
+ double winRate = (100d * (double) tank.Wins.DoubleValue() / tank.Battles.DoubleValue()); // - 48;
+
+ tank.Wn7 = CalculateWn7(tank.Battles.Value, tier, avdFrags, avgDamage, avgSpot, avgDef, winRate);
}
public static void CalculateWn7(this AccountInfoHistory account)
diff --git a/WotBlitzStatisticsPro.Logic/IWargamingAccounts.cs b/WotBlitzStatisticsPro.Logic/IWargamingAccounts.cs
index 34134cf..cbda944 100644
--- a/WotBlitzStatisticsPro.Logic/IWargamingAccounts.cs
+++ b/WotBlitzStatisticsPro.Logic/IWargamingAccounts.cs
@@ -12,5 +12,8 @@ namespace WotBlitzStatisticsPro.Logic
Task GetAccountInfoHistory(RealmType realm, long accountId, DateTime startDate,
RequestLanguage requestLanguage);
+
+ Task GetTankInfoHistory(RealmType realm, long accountId, long tankId, DateTime startDate,
+ RequestLanguage requestLanguage);
}
}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/WargamingAccounts.cs b/WotBlitzStatisticsPro.Logic/WargamingAccounts.cs
index 74c1efd..20eca77 100644
--- a/WotBlitzStatisticsPro.Logic/WargamingAccounts.cs
+++ b/WotBlitzStatisticsPro.Logic/WargamingAccounts.cs
@@ -126,5 +126,41 @@ namespace WotBlitzStatisticsPro.Logic
}
return contextData?.Response ?? new AccountInfoHistoryResponse();
}
+
+ public async Task GetTankInfoHistory(RealmType realm, long accountId, long tankId, DateTime startDate,
+ RequestLanguage requestLanguage)
+ {
+ var contextData = new TankHistoryInformationContextData(startDate, tankId);
+ try
+ {
+ var context = new OperationContext(new AccountRequest(accountId, realm, requestLanguage));
+ context.AddOrReplace(contextData);
+ var pipeline = new Pipeline(_operationFactory);
+
+ pipeline.AddOperation()
+ .AddOperation()
+ .AddOperation()
+ .AddOperation()
+ .AddOperation()
+ .AddOperation()
+ .AddOperation()
+ .AddOperation()
+ ;
+
+ var firstOperation = pipeline.Build();
+ if (firstOperation != null)
+ {
+ await firstOperation
+ .Invoke(context, null)
+ .ConfigureAwait(false);
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "GetAccountInfoHistory error");
+ throw;
+ }
+ return contextData?.Response ?? new TankInfoHistoryResponse();
+ }
}
}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs b/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
index db5ac71..86a6331 100644
--- a/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
+++ b/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
@@ -70,6 +70,9 @@ namespace WotBlitzStatisticsPro.Logic
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
+ services.AddTransient();
+ services.AddTransient();
services.AddTransient(serviceProvider =>
new ServiceProviderOperationFactory(serviceProvider));