using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using IronNestStats.Core.Stats; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace IronNestStats.Core.Stats { public static class StatCatalog { private static readonly StatDefinition[] Definitions = new StatDefinition[50] { D("MissionTime", "STR_MISSION_TIME", "Mission Time", "任务时间", StatFormat.Duration), D("CounterBatteryTimeRemaining", null, "Counter-battery Time", "反炮兵剩余时间", StatFormat.Duration), D("Kills", "STR_STAT_KILLS", "Kills", "击杀总数", StatFormat.Count), D("TargetKills", "STR_TARGETS_DESTROYED", "Target Kills", "目标击杀", StatFormat.Count), D("EnemyKills", "STR_STAT_ENEMY_KILLS", "Enemy Kills", "敌军击杀", StatFormat.Count), D("AllyKills", "STR_STAT_ALLIES_KILLED", "Allied Kills", "友军击杀", StatFormat.Count), D("StarsKilled", null, "Stars Killed", "星级目标击杀", StatFormat.Count), D("ShotsFiredAll", null, "All Shots", "所有射击", StatFormat.Count), D("ShotsFired", "STR_STAT_SHOTS_FIRED", "Shots Fired", "射击次数", StatFormat.Count), D("ShotsHit", null, "Shots Hit", "命中射击", StatFormat.Count), D("STARUsed", null, "STAR Used", "STAR 使用", StatFormat.Count), D("AverageImpactDistanceFromNearestTarget", null, "Average Impact Distance", "平均落点距离", StatFormat.Decimal), D("FirstShotTime", null, "First Shot Time", "首次射击时刻", StatFormat.Duration), D("LastTargetDestroyedTime", null, "Last Target Time", "最后目标摧毁时刻", StatFormat.Duration), D("RequisitionPointsSpent", "STR_STAT_REQUISITION_SPENT", "Requisition Spent", "征用点消耗", StatFormat.Decimal), D("ReconUsed", null, "Recon Used", "侦察使用", StatFormat.Count), D("ReconUsedAfterFirstShot", null, "Recon After First Shot", "首发后侦察", StatFormat.Count), D("LongestKillStreak", "STR_STAT_KILLSTREAK", "Longest Kill Streak", "最长连杀", StatFormat.Count), D("MostKillsBySingleImpact", "STR_STAT_MOST_KILLS_BY_IMPACT", "Most Kills by One Impact", "单次爆炸最多击杀", StatFormat.Count), D("BestThreeKillWindowSeconds", null, "Fastest Three Kills", "最快三杀窗口", StatFormat.Duration), D("AccuracyPercent", "STR_STAT_ACCURACY", "Accuracy", "命中率", StatFormat.Percent), D("MissPercent", null, "Miss Rate", "未命中率", StatFormat.Percent), D("ShotsMissed", "STR_MISSED_SHOTS", "Shots Missed", "未命中射击", StatFormat.Count), D("KillsPerShot", null, "Kills per Shot", "每发击杀", StatFormat.Decimal), D("KillsPerHit", "STR_STAT_KILLS_PER_HIT", "Kills per Hit", "每次命中击杀", StatFormat.Decimal), D("TargetsPerShot", null, "Targets per Shot", "每发目标击杀", StatFormat.Decimal), D("FriendlyFirePercent", null, "Friendly-fire Rate", "友军误伤率", StatFormat.Percent), D("EnemyKillPercent", null, "Enemy Kill Share", "敌军击杀占比", StatFormat.Percent), D("TargetKillPercent", null, "Target Kill Share", "目标击杀占比", StatFormat.Percent), D("AverageKillsPerImpact", null, "Average Kills per Impact", "平均每次爆炸击杀", StatFormat.Decimal), D("AverageStarsPerKill", null, "Average Stars per Kill", "平均每次击杀星级", StatFormat.Decimal), D("MissionTimeMinutes", null, "Mission Minutes", "任务分钟数", StatFormat.Decimal), D("TimeToFirstShot", null, "Time to First Shot", "首次开火用时", StatFormat.Duration), D("TimeToLastTargetKill", null, "Time to Last Target", "最后目标击杀用时", StatFormat.Duration), D("TimeFromFirstShotToLastTargetKill", null, "First Shot to Last Target", "首发至最后目标", StatFormat.Duration), D("ShotsPerMinute", null, "Shots per Minute", "每分钟射击", StatFormat.Decimal), D("KillsPerMinute", null, "Kills per Minute", "每分钟击杀", StatFormat.Decimal), D("RequisitionPerKill", null, "Requisition per Kill", "每次击杀消耗", StatFormat.Decimal), D("RequisitionPerTarget", null, "Requisition per Target", "每个目标消耗", StatFormat.Decimal), D("ReconAfterFirstShotPercent", null, "Recon after First Shot", "首发后侦察占比", StatFormat.Percent), D("STARUsagePercent", null, "STAR Usage", "STAR 使用率", StatFormat.Percent), D("PerfectAccuracy", null, "Perfect Accuracy", "完美命中", StatFormat.Boolean), D("NoFriendlyFire", null, "No Friendly Fire", "无友军误伤", StatFormat.Boolean), D("NoReconUsed", null, "No Recon Used", "未使用侦察", StatFormat.Boolean), D("NoSTARUsed", null, "No STAR Used", "未使用 STAR", StatFormat.Boolean), D("MultiKillShots", null, "Multi-kill Shots", "多杀射击", StatFormat.Count), D("TripleKillShots", null, "Triple-kill Shots", "三杀射击", StatFormat.Count), D("DirectHits", null, "Direct Hits", "直接命中", StatFormat.Count), D("MaxHitStreak", null, "Maximum Hit Streak", "最高连续命中", StatFormat.Count), D("CurrentRequisitionPoints", null, "Current Requisition", "当前征用点", StatFormat.Decimal) }; private static readonly Dictionary ById = Definitions.ToDictionary((StatDefinition d) => d.Id, StringComparer.OrdinalIgnoreCase); public static IEnumerable All => Definitions; public static StatDefinition Find(string id) { if (id == null || !ById.TryGetValue(id, out var value)) { return null; } return value; } private static StatDefinition D(string id, string key, string en, string zh, StatFormat format) { return new StatDefinition(id, key, en, zh, format); } } public enum StatFormat { Count, Decimal, Percent, Duration, Boolean } public sealed class StatDefinition { public string Id { get; } public string GameLocalizationKey { get; } public string EnglishLabel { get; } public string SimplifiedChineseLabel { get; } public StatFormat Format { get; } public StatDefinition(string id, string gameLocalizationKey, string englishLabel, string simplifiedChineseLabel, StatFormat format) { Id = id; GameLocalizationKey = gameLocalizationKey; EnglishLabel = englishLabel; SimplifiedChineseLabel = simplifiedChineseLabel; Format = format; } } public static class StatsCalculator { public static void AddDerivedValues(IDictionary values) { if (values == null) { throw new ArgumentNullException("values"); } double num = Get(values, "ShotsFired"); double num2 = Get(values, "ShotsHit"); double num3 = Get(values, "Kills"); double num4 = Get(values, "TargetKills"); double num5 = Get(values, "AllyKills"); double numerator = Get(values, "EnemyKills"); double numerator2 = Get(values, "RequisitionPointsSpent"); double num6 = Get(values, "MissionTime"); double num7 = Get(values, "ReconUsed"); double numerator3 = Get(values, "ReconUsedAfterFirstShot"); double num8 = Get(values, "STARUsed"); SetIfMissing(values, "ShotsMissed", Math.Max(0.0, num - num2)); SetIfMissing(values, "AccuracyPercent", Ratio(num2, num) * 100.0); SetIfMissing(values, "MissPercent", Ratio(Get(values, "ShotsMissed"), num) * 100.0); SetIfMissing(values, "KillsPerShot", Ratio(num3, num)); SetIfMissing(values, "KillsPerHit", Ratio(num3, num2)); SetIfMissing(values, "TargetsPerShot", Ratio(num4, num)); SetIfMissing(values, "FriendlyFirePercent", Ratio(num5, num3) * 100.0); SetIfMissing(values, "EnemyKillPercent", Ratio(numerator, num3) * 100.0); SetIfMissing(values, "TargetKillPercent", Ratio(num4, num3) * 100.0); SetIfMissing(values, "MissionTimeMinutes", num6 / 60.0); SetIfMissing(values, "ShotsPerMinute", Ratio(num, num6 / 60.0)); SetIfMissing(values, "KillsPerMinute", Ratio(num3, num6 / 60.0)); SetIfMissing(values, "RequisitionPerKill", Ratio(numerator2, num3)); SetIfMissing(values, "RequisitionPerTarget", Ratio(numerator2, num4)); SetIfMissing(values, "ReconAfterFirstShotPercent", Ratio(numerator3, num7) * 100.0); SetIfMissing(values, "STARUsagePercent", Ratio(num8, num) * 100.0); SetIfMissing(values, "PerfectAccuracy", (num > 0.0 && num2 >= num) ? 1 : 0); SetIfMissing(values, "NoFriendlyFire", (num5 <= 0.0) ? 1 : 0); SetIfMissing(values, "NoReconUsed", (num7 <= 0.0) ? 1 : 0); SetIfMissing(values, "NoSTARUsed", (num8 <= 0.0) ? 1 : 0); } public static double Get(IDictionary values, string id) { if (!values.TryGetValue(id, out var value) || double.IsNaN(value) || double.IsInfinity(value)) { return 0.0; } return value; } private static double Ratio(double numerator, double denominator) { if (!(Math.Abs(denominator) < 1E-06)) { return numerator / denominator; } return 0.0; } private static void SetIfMissing(IDictionary values, string id, double value) { if (!values.ContainsKey(id)) { values[id] = value; } } } } namespace IronNestStats.Core.Models { public sealed class MedalConditionSnapshot { public string StatisticId { get; } public double CurrentValue { get; } public string Comparison { get; } public double TargetValue { get; } public IDictionary InputValues { get; } public MedalConditionSnapshot(string statisticId, double currentValue, string comparison, double targetValue, IDictionary inputValues) { StatisticId = statisticId ?? "Value"; CurrentValue = currentValue; Comparison = comparison ?? "?"; TargetValue = targetValue; InputValues = inputValues ?? new Dictionary(); } } public sealed class MedalSnapshot { public string Name { get; } public double Progress { get; } public IList Tiers { get; } public MedalSnapshot(string name, double progress, IList tiers) { Name = name ?? "Medal"; Progress = ((progress < 0.0) ? 0.0 : ((progress > 1.0) ? 1.0 : progress)); Tiers = tiers ?? new List(); } } public sealed class MedalTierSnapshot { public string Tier { get; } public bool Achieved { get; } public double Progress { get; } public IList Conditions { get; } public MedalTierSnapshot(string tier, bool achieved, double progress, IList conditions) { Tier = tier ?? string.Empty; Achieved = achieved; Progress = ((progress < 0.0) ? 0.0 : ((progress > 1.0) ? 1.0 : progress)); Conditions = conditions ?? new List(); } } public sealed class StatsSnapshot { public bool Active { get; } public string MissionName { get; } public string Language { get; } public IDictionary Statistics { get; } public IList Medals { get; } public StatsSnapshot(bool active, string missionName, string language, IDictionary statistics, IList medals) { Active = active; MissionName = missionName ?? string.Empty; Language = language ?? "English"; Statistics = statistics ?? new Dictionary(); Medals = medals ?? new List(); } public static StatsSnapshot Inactive(string language) { return new StatsSnapshot(active: false, string.Empty, language, new Dictionary(), new List()); } } } namespace IronNestStats.Core.Formatting { public static class ValueFormatter { public static string Format(double value, StatFormat format, bool chinese) { if (double.IsNaN(value) || double.IsInfinity(value)) { return "-"; } switch (format) { case StatFormat.Count: return Math.Round(value).ToString("0", CultureInfo.InvariantCulture); case StatFormat.Decimal: return value.ToString("0.00", CultureInfo.InvariantCulture); case StatFormat.Percent: return value.ToString("0.0", CultureInfo.InvariantCulture) + "%"; case StatFormat.Boolean: if (value == 0.0) { if (!chinese) { return "No"; } return "否"; } if (!chinese) { return "Yes"; } return "是"; case StatFormat.Duration: { int num = Math.Max(0, (int)Math.Round(value)); if (num < 60) { return num.ToString(CultureInfo.InvariantCulture) + (chinese ? " 秒" : " s"); } return (num / 60).ToString(CultureInfo.InvariantCulture) + ":" + (num % 60).ToString("00", CultureInfo.InvariantCulture); } default: return value.ToString(CultureInfo.InvariantCulture); } } } }