Decompiled source of MissionStats v0.1.0

Mods/MissionStats.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using IronNestStats.Core.Formatting;
using IronNestStats.Core.Models;
using IronNestStats.Core.Stats;
using IronNestStats.Melon;
using IronNestStats.Melon.Configuration;
using IronNestStats.Melon.Game;
using IronNestStats.Melon.Runtime;
using IronNestStats.Melon.UI;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Plugin), "MissionStats", "0.1.0", "rvql", null)]
[assembly: MelonGame("Iron Nest", "Iron Nest Heavy Turret Simulator")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace IronNestStats.Melon
{
	public sealed class Plugin : MelonMod
	{
		private ModRuntime _runtime;

		public override void OnInitializeMelon()
		{
			ModSettings settings = new ModSettings();
			_runtime = new ModRuntime(settings, delegate(string message)
			{
				((MelonBase)this).LoggerInstance.Msg(message);
			}, delegate(string message)
			{
				((MelonBase)this).LoggerInstance.Warning(message);
			});
			((MelonBase)this).LoggerInstance.Msg("MissionStats loaded. No native game-method hooks are used.");
		}

		public override void OnUpdate()
		{
			if (_runtime != null)
			{
				_runtime.Update();
			}
		}

		public override void OnGUI()
		{
			if (_runtime != null)
			{
				_runtime.Draw();
			}
		}

		public override void OnDeinitializeMelon()
		{
			if (_runtime != null)
			{
				_runtime.Shutdown();
			}
			_runtime = null;
		}
	}
}
namespace IronNestStats.Melon.UI
{
	internal sealed class OverlayRenderer
	{
		private sealed class MedalPanelLayout
		{
			public float PanelWidth { get; }

			public float HeaderHeight { get; }

			public float MissionTitleHeight { get; }

			public float ContentHeight { get; }

			public IList<float> MedalTitleHeights { get; }

			public IList<float> RelatedStatisticHeights { get; }

			public ConditionTableLayout ConditionTable { get; }

			public MedalPanelLayout(float panelWidth, float headerHeight, float missionTitleHeight, float contentHeight, IList<float> medalTitleHeights, IList<float> relatedStatisticHeights, ConditionTableLayout conditionTable)
			{
				PanelWidth = panelWidth;
				HeaderHeight = headerHeight;
				MissionTitleHeight = missionTitleHeight;
				ContentHeight = contentHeight;
				MedalTitleHeights = medalTitleHeights;
				RelatedStatisticHeights = relatedStatisticHeights;
				ConditionTable = conditionTable;
			}
		}

		private sealed class ConditionTableLayout
		{
			public float LabelWidth { get; }

			public float[] TierWidths { get; }

			public float TotalWidth { get; }

			public ConditionTableLayout(float labelWidth, float[] tierWidths, float totalWidth)
			{
				LabelWidth = labelWidth;
				TierWidths = tierWidths;
				TotalWidth = totalWidth;
			}
		}

		private sealed class ConditionTableRow
		{
			public string Label { get; }

			public string[] TargetValues { get; }

			public ConditionTableRow(string label)
			{
				Label = label;
				TargetValues = new string[3];
			}
		}

		private sealed class StatRow
		{
			public string Label { get; }

			public string Value { get; }

			public StatRow(string label, string value)
			{
				Label = label;
				Value = value;
			}
		}

		private const float ProgressBarWidth = 240f;

		private GUIStyle _panelTitle;

		private GUIStyle _missionTitle;

		private GUIStyle _medalName;

		private GUIStyle _conditionText;

		private GUIStyle _relatedStats;

		private GUIStyle _tableHeader;

		private GUIStyle _conditionValue;

		private GUIStyle _statLabel;

		private GUIStyle _statValue;

		private GUIStyle _tickLabel;

		public void Draw(StatsSnapshot snapshot, ModSettings settings, bool showMedals, bool showStats, GameLocalizationService localization)
		{
			EnsureStyles();
			MedalPanelLayout medalPanelLayout = null;
			if (showMedals)
			{
				medalPanelLayout = CreateMedalPanelLayout(snapshot, settings, localization);
				DrawMedalPanel(snapshot, settings, localization, medalPanelLayout);
			}
			if (showStats)
			{
				DrawStatisticsPanel(snapshot, settings, localization, medalPanelLayout?.PanelWidth ?? 0f);
			}
		}

		private void DrawMedalPanel(StatsSnapshot snapshot, ModSettings settings, GameLocalizationService localization, MedalPanelLayout layout)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			bool flag = localization.IsChinese(snapshot.Language);
			float panelWidth = layout.PanelWidth;
			float val = Math.Min(Math.Max(320f, settings.PanelHeight.Value), (float)Screen.height - 32f);
			float num = Math.Min(Math.Max(220f, layout.ContentHeight), val);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor((float)Screen.width - panelWidth - 16f, 16f, panelWidth, num);
			if (IsPointerInside(val2))
			{
				DrawBackground(val2, settings.Opacity);
			}
			GUI.Label(new Rect(((Rect)(ref val2)).x + 16f, ((Rect)(ref val2)).y + 10f, ((Rect)(ref val2)).width - 32f, 20f), flag ? "任务" : "MISSION", _panelTitle);
			GUI.Label(new Rect(((Rect)(ref val2)).x + 16f, ((Rect)(ref val2)).y + 30f, ((Rect)(ref val2)).width - 32f, layout.MissionTitleHeight), snapshot.MissionName, _missionTitle);
			float num2 = ((Rect)(ref val2)).y + layout.HeaderHeight;
			MedalSnapshot val3 = null;
			Rect val5 = default(Rect);
			for (int i = 0; i < snapshot.Medals.Count; i++)
			{
				MedalSnapshot val4 = snapshot.Medals[i];
				float num3 = num2;
				float num4 = layout.MedalTitleHeights[i];
				GUI.Label(new Rect(((Rect)(ref val2)).x + 16f, num2, ((Rect)(ref val2)).width - 32f, num4), val4.Name, _medalName);
				num2 += num4 + 2f;
				((Rect)(ref val5))..ctor(((Rect)(ref val2)).right - 16f - 240f, num2, 240f, 18f);
				DrawSolid(val5, new Color(0.13f, 0.16f, 0.2f, 0.95f));
				DrawSolid(new Rect(((Rect)(ref val5)).x + 2f, ((Rect)(ref val5)).y + 2f, Math.Max(0f, (((Rect)(ref val5)).width - 4f) * (float)val4.Progress), ((Rect)(ref val5)).height - 4f), ProgressColor(val4.Progress));
				DrawTierTicks(val5, snapshot.Language, localization);
				num2 += 21f;
				string text = BuildRelatedStatistics(val4, snapshot.Language, localization);
				float num5 = layout.RelatedStatisticHeights[i];
				GUI.Label(new Rect(((Rect)(ref val2)).x + 16f, num2, ((Rect)(ref val2)).width - 32f, num5), text, _relatedStats);
				num2 += num5 + 2f;
				num2 += 7f;
				if (IsPointerInside(new Rect(((Rect)(ref val2)).x + 16f, num3, ((Rect)(ref val2)).width - 32f, num2 - num3)))
				{
					val3 = val4;
				}
				if (num2 > ((Rect)(ref val2)).bottom - 20f)
				{
					break;
				}
			}
			if (val3 != null && GetConditionRowCount(val3) > 0 && num2 < ((Rect)(ref val2)).bottom - 40f)
			{
				GUI.Label(new Rect(((Rect)(ref val2)).x + 16f, num2, ((Rect)(ref val2)).width - 32f, 22f), val3.Name, _medalName);
				DrawConditionTable(val2, num2 + 24f, val3, snapshot.Language, localization, layout.ConditionTable);
			}
		}

		private MedalPanelLayout CreateMedalPanelLayout(StatsSnapshot snapshot, ModSettings settings, GameLocalizationService localization)
		{
			float num = Math.Min(Math.Max(380f, settings.MedalPanelWidth.Value), (float)Screen.width - 32f) - 32f;
			ConditionTableLayout conditionTableLayout = CreateConditionTableLayout(snapshot.Medals, snapshot.Language, localization, 240f, num);
			float val = Math.Max(240f, conditionTableLayout.TotalWidth);
			val = Math.Max(val, MeasureWidth(_missionTitle, snapshot.MissionName) + 4f);
			foreach (MedalSnapshot medal in snapshot.Medals)
			{
				val = Math.Max(val, MeasureWidth(_medalName, medal.Name) + 4f);
			}
			val = Math.Min(val, num);
			float panelWidth = val + 32f;
			float num2 = Math.Max(32f, MeasureHeight(_missionTitle, snapshot.MissionName, val));
			float num3 = 30f + num2 + 8f;
			List<float> list = new List<float>();
			List<float> list2 = new List<float>();
			float num4 = 0f;
			foreach (MedalSnapshot medal2 in snapshot.Medals)
			{
				float num5 = Math.Max(22f, MeasureHeight(_medalName, medal2.Name, val));
				string value = BuildRelatedStatistics(medal2, snapshot.Language, localization);
				float num6 = Math.Max(20f, MeasureHeight(_relatedStats, value, val));
				list.Add(num5);
				list2.Add(num6);
				num4 += num5 + num6 + 32f;
			}
			int maximumConditionRows = GetMaximumConditionRows(snapshot.Medals);
			float num7 = ((maximumConditionRows == 0) ? 0f : (56f + (float)maximumConditionRows * 34f));
			return new MedalPanelLayout(panelWidth, num3, num2, num3 + num4 + num7, list, list2, conditionTableLayout);
		}

		private ConditionTableLayout CreateConditionTableLayout(IList<MedalSnapshot> medals, string language, GameLocalizationService localization, float minimumWidth, float maximumWidth)
		{
			float num = 120f;
			float[] array = new float[3] { 40f, 40f, 40f };
			for (int i = 0; i < 3; i++)
			{
				array[i] = Math.Max(array[i], MeasureWidth(_tableHeader, localization.GetTierLabel(i switch
				{
					1 => "Silver", 
					0 => "Bronze", 
					_ => "Gold", 
				}, language)) + 16f);
			}
			foreach (MedalSnapshot medal in medals)
			{
				foreach (ConditionTableRow item in BuildConditionRows(medal, language, localization))
				{
					num = Math.Max(num, MeasureWidth(_conditionText, item.Label) + 18f);
					for (int j = 0; j < 3; j++)
					{
						array[j] = Math.Max(array[j], MeasureWidth(_conditionValue, item.TargetValues[j]) + 16f);
					}
				}
			}
			float num2 = array[0] + array[1] + array[2];
			float num3 = num + num2;
			if (num3 > maximumWidth)
			{
				num = Math.Max(120f, maximumWidth - num2);
				num3 = num + num2;
				if (num3 > maximumWidth)
				{
					float val = Math.Max(40f, (maximumWidth - 120f) / 3f);
					for (int k = 0; k < 3; k++)
					{
						array[k] = Math.Min(array[k], val);
					}
					num2 = array[0] + array[1] + array[2];
					num = Math.Max(120f, maximumWidth - num2);
					num3 = num + num2;
				}
			}
			if (num3 < minimumWidth)
			{
				num += minimumWidth - num3;
				num3 = minimumWidth;
			}
			return new ConditionTableLayout(num, array, Math.Min(num3, maximumWidth));
		}

		private static float MeasureWidth(GUIStyle style, string value)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(value))
			{
				return 0f;
			}
			return style.CalcSize(new GUIContent(value)).x;
		}

		private static float MeasureHeight(GUIStyle style, string value, float width)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if (string.IsNullOrEmpty(value))
			{
				return 0f;
			}
			return style.CalcHeight(new GUIContent(value), width);
		}

		private string BuildRelatedStatistics(MedalSnapshot medal, string language, GameLocalizationService localization)
		{
			Dictionary<string, double> dictionary = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);
			foreach (MedalTierSnapshot tier in medal.Tiers)
			{
				foreach (MedalConditionSnapshot condition in tier.Conditions)
				{
					if (condition.InputValues.Count > 0)
					{
						foreach (KeyValuePair<string, double> inputValue in condition.InputValues)
						{
							dictionary[inputValue.Key] = inputValue.Value;
						}
					}
					else
					{
						dictionary[condition.StatisticId] = condition.CurrentValue;
					}
				}
			}
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, double> item in dictionary)
			{
				list.Add(localization.GetStatLabel(item.Key, language) + " " + item.Value.ToString("0.##", CultureInfo.InvariantCulture));
			}
			return string.Join(" · ", list);
		}

		private float DrawConditionTable(Rect panel, float y, MedalSnapshot medal, string language, GameLocalizationService localization, ConditionTableLayout layout)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			IList<ConditionTableRow> list = BuildConditionRows(medal, language, localization);
			if (list.Count == 0)
			{
				return y;
			}
			float totalWidth = layout.TotalWidth;
			float num = ((Rect)(ref panel)).right - 16f - totalWidth;
			float labelWidth = layout.LabelWidth;
			float num2 = 22f + (float)list.Count * 34f;
			Color color = default(Color);
			((Color)(ref color))..ctor(0.4f, 0.52f, 0.6f, 0.55f);
			DrawSolid(new Rect(num, y, totalWidth, 1f), color);
			DrawSolid(new Rect(num, y + 22f, totalWidth, 1f), color);
			DrawSolid(new Rect(num, y, 1f, num2), color);
			DrawSolid(new Rect(num + labelWidth, y, 1f, num2), color);
			for (int i = 1; i <= 3; i++)
			{
				DrawSolid(new Rect(num + labelWidth + SumTierWidths(layout, i), y, 1f, num2), color);
			}
			for (int j = 0; j < 3; j++)
			{
				GUI.Label(new Rect(num + labelWidth + SumTierWidths(layout, j) + 5f, y + 1f, layout.TierWidths[j] - 10f, 20f), localization.GetTierLabel(j switch
				{
					1 => "Silver", 
					0 => "Bronze", 
					_ => "Gold", 
				}, language), _tableHeader);
			}
			for (int k = 0; k < list.Count; k++)
			{
				float num3 = y + 22f + (float)k * 34f;
				DrawSolid(new Rect(num, num3 + 34f, totalWidth, 1f), color);
				GUI.Label(new Rect(num + 7f, num3 + 2f, labelWidth - 14f, 30f), list[k].Label, _conditionText);
				for (int l = 0; l < 3; l++)
				{
					GUI.Label(new Rect(num + labelWidth + SumTierWidths(layout, l) + 5f, num3 + 2f, layout.TierWidths[l] - 10f, 30f), list[k].TargetValues[l] ?? string.Empty, _conditionValue);
				}
			}
			return y + num2 + 10f;
		}

		private static MedalTierSnapshot FindTier(MedalSnapshot medal, string tierName)
		{
			foreach (MedalTierSnapshot tier in medal.Tiers)
			{
				if (string.Equals(tier.Tier, tierName, StringComparison.OrdinalIgnoreCase))
				{
					return tier;
				}
			}
			return null;
		}

		private static IList<ConditionTableRow> BuildConditionRows(MedalSnapshot medal, string language, GameLocalizationService localization)
		{
			List<ConditionTableRow> list = new List<ConditionTableRow>();
			Dictionary<string, ConditionTableRow> dictionary = new Dictionary<string, ConditionTableRow>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < 3; i++)
			{
				MedalTierSnapshot val = FindTier(medal, i switch
				{
					1 => "Silver", 
					0 => "Bronze", 
					_ => "Gold", 
				});
				if (val == null)
				{
					continue;
				}
				Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
				foreach (MedalConditionSnapshot condition in val.Conditions)
				{
					string conditionBaseKey = GetConditionBaseKey(condition);
					dictionary2.TryGetValue(conditionBaseKey, out var value);
					dictionary2[conditionBaseKey] = value + 1;
					string key = conditionBaseKey + "\u001f" + value.ToString(CultureInfo.InvariantCulture);
					if (!dictionary.TryGetValue(key, out var value2))
					{
						value2 = (dictionary[key] = new ConditionTableRow(localization.GetStatLabel(condition.StatisticId, language) + " " + DisplayComparison(condition.Comparison)));
						list.Add(value2);
					}
					value2.TargetValues[i] = FormatConditionNumber(condition.TargetValue);
				}
			}
			return list;
		}

		private static int GetConditionRowCount(MedalSnapshot medal)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (MedalTierSnapshot tier in medal.Tiers)
			{
				Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
				foreach (MedalConditionSnapshot condition in tier.Conditions)
				{
					string conditionBaseKey = GetConditionBaseKey(condition);
					dictionary.TryGetValue(conditionBaseKey, out var value);
					dictionary[conditionBaseKey] = value + 1;
					hashSet.Add(conditionBaseKey + "\u001f" + value.ToString(CultureInfo.InvariantCulture));
				}
			}
			return hashSet.Count;
		}

		private static string GetConditionBaseKey(MedalConditionSnapshot condition)
		{
			return (condition.StatisticId ?? "Value") + "\u001f" + (condition.Comparison ?? "?");
		}

		private static int GetMaximumConditionRows(IList<MedalSnapshot> medals)
		{
			int num = 0;
			foreach (MedalSnapshot medal in medals)
			{
				num = Math.Max(num, GetConditionRowCount(medal));
			}
			return num;
		}

		private static float SumTierWidths(ConditionTableLayout layout, int exclusiveEnd)
		{
			float num = 0f;
			for (int i = 0; i < exclusiveEnd; i++)
			{
				num += layout.TierWidths[i];
			}
			return num;
		}

		private static string DisplayComparison(string comparison)
		{
			object obj;
			switch (comparison)
			{
			default:
				obj = comparison;
				if (obj == null)
				{
					return "?";
				}
				break;
			case "!=":
				return "≠";
			case "<=":
				return "≤";
			case ">=":
				obj = "≥";
				break;
			}
			return (string)obj;
		}

		private static string FormatConditionNumber(double value)
		{
			if (double.IsNaN(value))
			{
				return "—";
			}
			if (double.IsPositiveInfinity(value))
			{
				return "∞";
			}
			if (double.IsNegativeInfinity(value))
			{
				return "-∞";
			}
			return value.ToString("0.##", CultureInfo.InvariantCulture);
		}

		private void DrawStatisticsPanel(StatsSnapshot snapshot, ModSettings settings, GameLocalizationService localization, float medalPanelWidth)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			bool flag = localization.IsChinese(snapshot.Language);
			float num = ((medalPanelWidth > 0f) ? (medalPanelWidth + 32f) : 0f);
			float num2 = Math.Min(Math.Max(640f, settings.StatsPanelWidth.Value), (float)Screen.width - num - 32f);
			if (num2 < 540f)
			{
				return;
			}
			float num3 = Math.Min(Math.Max(260f, settings.PanelHeight.Value), (float)Screen.height - 32f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(16f, 16f, num2, num3);
			DrawBackground(val, settings.Opacity);
			GUI.Label(new Rect(((Rect)(ref val)).x + 18f, ((Rect)(ref val)).y + 10f, ((Rect)(ref val)).width - 36f, 26f), flag ? "详细统计" : "DETAILED STATISTICS", _panelTitle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 18f, ((Rect)(ref val)).y + 36f, ((Rect)(ref val)).width - 36f, 22f), snapshot.MissionName, _statLabel);
			List<StatRow> list = new List<StatRow>();
			foreach (StatDefinition item in StatCatalog.All)
			{
				if (snapshot.Statistics.TryGetValue(item.Id, out var value))
				{
					list.Add(new StatRow(localization.GetStatLabel(item.Id, snapshot.Language), ValueFormatter.Format(value, item.Format, flag)));
				}
			}
			DrawStatRows(val, list);
		}

		private void DrawStatRows(Rect panel, IList<StatRow> rows)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			float num = ((Rect)(ref panel)).height - 64f - 14f;
			int num2 = Math.Max(1, (int)(num / 21f));
			int num3 = Math.Min(3, Math.Max(2, (int)Math.Ceiling((double)rows.Count / (double)num2)));
			float num4 = (((Rect)(ref panel)).width - 36f - 16f * (float)(num3 - 1)) / (float)num3;
			for (int i = 0; i < rows.Count && i < num2 * num3; i++)
			{
				int num5 = i / num2;
				int num6 = i % num2;
				float num7 = ((Rect)(ref panel)).x + 18f + (float)num5 * (num4 + 16f);
				float num8 = ((Rect)(ref panel)).y + 64f + (float)num6 * 21f;
				float num9 = num4 * 0.7f;
				GUI.Label(new Rect(num7, num8, num9, 21f), rows[i].Label, _statLabel);
				GUI.Label(new Rect(num7 + num9, num8, num4 - num9, 21f), rows[i].Value, _statValue);
			}
		}

		private static void DrawBackground(Rect rect, float opacity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			DrawSolid(rect, new Color(0.025f, 0.035f, 0.05f, opacity));
			DrawSolid(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, 3f, ((Rect)(ref rect)).height), new Color(0.22f, 0.62f, 0.86f, Math.Min(1f, opacity + 0.15f)));
		}

		private static bool IsPointerInside(Rect rect)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Mouse current = Mouse.current;
			if (current != null)
			{
				Vector2 val = ((InputControl<Vector2>)(object)((Pointer)current).position).ReadValue();
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(val.x, (float)Screen.height - val.y);
				return ((Rect)(ref rect)).Contains(val2);
			}
			Event current2 = Event.current;
			if (current2 != null)
			{
				return ((Rect)(ref rect)).Contains(current2.mousePosition);
			}
			return false;
		}

		private static void DrawSolid(Rect rect, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Color color2 = GUI.color;
			GUI.color = color;
			GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color2;
		}

		private static Color ProgressColor(double progress)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (progress >= 1.0)
			{
				return new Color(0.88f, 0.69f, 0.2f, 1f);
			}
			if (progress >= 0.66)
			{
				return new Color(0.28f, 0.72f, 0.45f, 1f);
			}
			return new Color(0.2f, 0.55f, 0.82f, 1f);
		}

		private void DrawTierTicks(Rect bar, string language, GameLocalizationService localization)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 3; i++)
			{
				float num = ((float)i + 1f) / 3f;
				float num2 = ((Rect)(ref bar)).x + 2f + (((Rect)(ref bar)).width - 4f) * num;
				if (i == 2)
				{
					num2 = ((Rect)(ref bar)).right - 2f;
				}
				Color color = (Color)(i switch
				{
					1 => new Color(0.76f, 0.8f, 0.84f, 1f), 
					0 => new Color(0.78f, 0.43f, 0.18f, 1f), 
					_ => new Color(0.96f, 0.76f, 0.2f, 1f), 
				});
				DrawSolid(new Rect(num2 - 1f, ((Rect)(ref bar)).y + 1f, 2f, ((Rect)(ref bar)).height - 2f), color);
				string text = i switch
				{
					1 => "Silver", 
					0 => "Bronze", 
					_ => "Gold", 
				};
				string tierLabel = localization.GetTierLabel(text, language);
				string text2 = (string.IsNullOrEmpty(tierLabel) ? text.Substring(0, 1) : tierLabel.Substring(0, 1));
				GUI.Label(new Rect(num2 - 22f, ((Rect)(ref bar)).y, 18f, ((Rect)(ref bar)).height), text2, _tickLabel);
			}
		}

		private void EnsureStyles()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			if (_panelTitle == null)
			{
				_panelTitle = Style(13, (FontStyle)1, (TextAnchor)5, new Color(0.52f, 0.74f, 0.88f, 1f));
				_missionTitle = Style(19, (FontStyle)1, (TextAnchor)5, new Color(0.96f, 0.97f, 0.99f, 1f));
				_missionTitle.wordWrap = true;
				_medalName = Style(15, (FontStyle)1, (TextAnchor)5, new Color(0.93f, 0.94f, 0.96f, 1f));
				_medalName.wordWrap = true;
				_conditionText = Style(10, (FontStyle)0, (TextAnchor)3, new Color(0.68f, 0.74f, 0.79f, 1f));
				_conditionText.wordWrap = true;
				_relatedStats = Style(10, (FontStyle)0, (TextAnchor)5, new Color(0.7f, 0.78f, 0.84f, 1f));
				_relatedStats.wordWrap = true;
				_tableHeader = Style(11, (FontStyle)1, (TextAnchor)4, new Color(0.88f, 0.91f, 0.94f, 1f));
				_conditionValue = Style(11, (FontStyle)1, (TextAnchor)4, new Color(0.96f, 0.82f, 0.38f, 1f));
				_statLabel = Style(13, (FontStyle)0, (TextAnchor)3, new Color(0.76f, 0.82f, 0.87f, 1f));
				_statValue = Style(13, (FontStyle)1, (TextAnchor)5, new Color(0.96f, 0.82f, 0.38f, 1f));
				_tickLabel = Style(9, (FontStyle)1, (TextAnchor)5, Color.white);
			}
		}

		private static GUIStyle Style(int size, FontStyle fontStyle, TextAnchor alignment, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			GUIStyle val = new GUIStyle
			{
				fontSize = size,
				fontStyle = fontStyle,
				alignment = alignment
			};
			val.normal.textColor = color;
			return val;
		}
	}
}
namespace IronNestStats.Melon.Runtime
{
	internal sealed class ModRuntime
	{
		private readonly ModSettings _settings;

		private readonly Action<string> _info;

		private readonly Action<string> _warning;

		private readonly IronNestGameFacade _game;

		private readonly OverlayRenderer _renderer;

		private StatsSnapshot _snapshot;

		private bool _showMedals;

		private bool _showStats;

		private float _nextRefresh;

		private float _nextErrorLog;

		private bool _active = true;

		private bool _lastMissionActive;

		private string _lastMissionName = string.Empty;

		public ModRuntime(ModSettings settings, Action<string> info, Action<string> warning)
		{
			_settings = settings;
			_info = info;
			_warning = warning;
			_game = new IronNestGameFacade();
			_renderer = new OverlayRenderer();
			_snapshot = StatsSnapshot.Inactive("English");
			_showMedals = settings.ShowMedalsByDefault.Value;
			_showStats = settings.ShowStatsByDefault.Value;
		}

		public void Update()
		{
			if (!_active)
			{
				return;
			}
			if (_settings.ToggleMedalsBinding.IsDown())
			{
				_showMedals = !_showMedals;
				_info("Medal panel: " + (_showMedals ? "shown" : "hidden"));
			}
			if (_settings.ToggleStatsBinding.IsDown())
			{
				_showStats = !_showStats;
				_info("Statistics panel: " + (_showStats ? "shown" : "hidden"));
			}
			if (Time.unscaledTime < _nextRefresh)
			{
				return;
			}
			_nextRefresh = Time.unscaledTime + _settings.RefreshSeconds;
			try
			{
				_snapshot = _game.Capture(_settings.MedalLimit, _settings.ShowMedalConditions.Value, _settings.ConditionLimit);
				if (_snapshot.Active != _lastMissionActive || (_snapshot.Active && _snapshot.MissionName != _lastMissionName))
				{
					if (_snapshot.Active && !_lastMissionActive)
					{
						_showMedals = _settings.ShowMedalsByDefault.Value;
						_showStats = _settings.ShowStatsByDefault.Value;
					}
					_lastMissionActive = _snapshot.Active;
					_lastMissionName = _snapshot.MissionName;
					_info(_snapshot.Active ? ("Mission statistics active: " + _snapshot.MissionName) : "Mission statistics inactive");
				}
			}
			catch (Exception ex)
			{
				_snapshot = StatsSnapshot.Inactive((_snapshot == null) ? "English" : _snapshot.Language);
				if (Time.unscaledTime >= _nextErrorLog)
				{
					_nextErrorLog = Time.unscaledTime + 5f;
					_warning("Statistics capture failed: " + ex);
				}
			}
		}

		public void Draw()
		{
			if (_active && _snapshot != null && _snapshot.Active && (_showMedals || _showStats))
			{
				_renderer.Draw(_snapshot, _settings, _showMedals, _showStats, _game.Localization);
			}
		}

		public void Shutdown()
		{
			_active = false;
		}
	}
}
namespace IronNestStats.Melon.Game
{
	internal sealed class GameLocalizationService
	{
		private readonly ReflectionBridge _bridge;

		public string CurrentLanguage
		{
			get
			{
				object instance = _bridge.GetStatic("Localisation.LocalisationManager", "Instance");
				string text = _bridge.Text(_bridge.Get(instance, "CurrentLanguage"));
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
				return "English";
			}
		}

		public GameLocalizationService(ReflectionBridge bridge)
		{
			_bridge = bridge;
		}

		public bool IsChinese(string language)
		{
			if (!string.IsNullOrEmpty(language))
			{
				return language.IndexOf("Chinese", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		public string ResolveIdentifier(object identifier, string fallback)
		{
			string text = _bridge.Text(_bridge.Invoke(identifier, "Get"));
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return fallback;
		}

		public string GetGameText(string key, string fallback)
		{
			if (string.IsNullOrEmpty(key))
			{
				return fallback;
			}
			object instance = _bridge.GetStatic("Localisation.LocalisationManager", "Instance");
			string text = _bridge.Text(_bridge.Invoke(instance, "Get", key));
			if (!string.IsNullOrEmpty(text) && !(text == key))
			{
				return text;
			}
			return fallback;
		}

		public string GetStatLabel(string statisticId, string language)
		{
			StatDefinition val = StatCatalog.Find(statisticId);
			if (val == null)
			{
				return LocalizeFormula(statisticId, language) ?? Humanize(statisticId);
			}
			string fallback = (IsChinese(language) ? val.SimplifiedChineseLabel : val.EnglishLabel);
			return GetGameText(val.GameLocalizationKey, fallback);
		}

		public string GetTierLabel(string tier, string language)
		{
			bool flag = string.Equals(tier, "Bronze", StringComparison.OrdinalIgnoreCase);
			bool flag2 = string.Equals(tier, "Silver", StringComparison.OrdinalIgnoreCase);
			if (Contains(language, "Chinese"))
			{
				bool flag3 = Contains(language, "Traditional");
				if (!flag)
				{
					if (!flag2)
					{
						if (!flag3)
						{
							return "金牌";
						}
						return "金牌";
					}
					if (!flag3)
					{
						return "银牌";
					}
					return "銀牌";
				}
				if (!flag3)
				{
					return "铜牌";
				}
				return "銅牌";
			}
			if (Contains(language, "Japanese"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "金メダル";
					}
					return "銀メダル";
				}
				return "銅メダル";
			}
			if (Contains(language, "Korean"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "금메달";
					}
					return "은메달";
				}
				return "동메달";
			}
			if (Contains(language, "French"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Or";
					}
					return "Argent";
				}
				return "Bronze";
			}
			if (Contains(language, "German"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Gold";
					}
					return "Silber";
				}
				return "Bronze";
			}
			if (Contains(language, "Spanish"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Oro";
					}
					return "Plata";
				}
				return "Bronce";
			}
			if (Contains(language, "Italian"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Oro";
					}
					return "Argento";
				}
				return "Bronzo";
			}
			if (Contains(language, "Portuguese"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Ouro";
					}
					return "Prata";
				}
				return "Bronze";
			}
			if (Contains(language, "Russian"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Золото";
					}
					return "Серебро";
				}
				return "Бронза";
			}
			if (Contains(language, "Polish"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Złoto";
					}
					return "Srebro";
				}
				return "Brąz";
			}
			if (Contains(language, "Turkish"))
			{
				if (!flag)
				{
					if (!flag2)
					{
						return "Altın";
					}
					return "Gümüş";
				}
				return "Bronz";
			}
			if (!flag)
			{
				if (!flag2)
				{
					return "Gold";
				}
				return "Silver";
			}
			return "Bronze";
		}

		private string LocalizeFormula(string value, string language)
		{
			if (string.IsNullOrEmpty(value))
			{
				return null;
			}
			for (int i = 1; i < value.Length - 1; i++)
			{
				char c = value[i];
				if (c == '+' || c == '-' || c == '*' || c == '/')
				{
					string statisticId = value.Substring(0, i);
					string statisticId2 = value.Substring(i + 1);
					string text = ((c == '/') ? " / " : c.ToString());
					return GetStatLabel(statisticId, language) + text + GetStatLabel(statisticId2, language);
				}
			}
			return null;
		}

		private static string Humanize(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "Value";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < value.Length; i++)
			{
				if (i > 0 && char.IsUpper(value[i]) && char.IsLower(value[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(value[i]);
			}
			return stringBuilder.ToString();
		}

		private static bool Contains(string value, string expected)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return value.IndexOf(expected, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}
	}
	internal sealed class IronNestGameFacade
	{
		private sealed class ExpressionInfo
		{
			public string Id { get; }

			public bool IsInline { get; }

			public IDictionary<string, double> InputValues { get; }

			public ExpressionInfo(string id, bool isInline, IDictionary<string, double> inputValues)
			{
				Id = id;
				IsInline = isInline;
				InputValues = inputValues;
			}

			public static ExpressionInfo ForStatistic(string id, double value)
			{
				Dictionary<string, double> dictionary = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);
				if (!string.IsNullOrEmpty(id))
				{
					dictionary[id] = value;
				}
				return new ExpressionInfo(id, isInline: false, dictionary);
			}
		}

		private static readonly string[] TrackedStatisticIds = new string[21]
		{
			"Kills", "TargetKills", "EnemyKills", "AllyKills", "StarsKilled", "ShotsFired", "ShotsHit", "STARUsed", "AverageImpactDistanceFromNearestTarget", "FirstShotTime",
			"LastTargetDestroyedTime", "RequisitionPointsSpent", "ReconUsed", "ReconUsedAfterFirstShot", "LongestKillStreak", "MostKillsBySingleImpact", "BestThreeKillWindowSeconds", "CounterBatteryTimeRemaining", "MissionStartTime", "MissionCompleteTime",
			"MissionEndTime"
		};

		private static readonly IDictionary<string, string> TrackerMembers = new Dictionary<string, string>
		{
			{ "MissionTime", "MissionTime_Mission" },
			{ "ShotsFired", "ShotsFired_Mission" },
			{ "TargetKills", "TargetsDestroyed_Mission" },
			{ "ShotsHit", "HitsOnTargets_Mission" },
			{ "ShotsMissed", "MissedShots_Mission" },
			{ "AccuracyPercent", "Accuracy_Mission" },
			{ "DirectHits", "DirectHits_Mission" },
			{ "MaxHitStreak", "MaxHitStreak_Mission" },
			{ "CurrentRequisitionPoints", "RequisitionPoints" }
		};

		private readonly ReflectionBridge _bridge = new ReflectionBridge();

		private readonly GameLocalizationService _localization;

		public GameLocalizationService Localization => _localization;

		public IronNestGameFacade()
		{
			_localization = new GameLocalizationService(_bridge);
		}

		public StatsSnapshot Capture(int maxMedals, bool includeConditions, int maxConditionsPerMedal)
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			string currentLanguage = _localization.CurrentLanguage;
			object obj = _bridge.GetStatic("MissionManager", "Instance");
			if (obj == null || !IsMissionActive(_bridge.Get(obj, "CurrentPhase")))
			{
				return StatsSnapshot.Inactive(currentLanguage);
			}
			object obj2 = _bridge.Get(obj, "CurrentMission");
			object instance = _bridge.Get(obj, "CurrentMissionState");
			object trackedValues = _bridge.Get(instance, "TrackingValues");
			object tracker = _bridge.GetStatic("MissionStatsTracker", "Instance");
			string text = _localization.ResolveIdentifier(_bridge.Get(obj2, "MissionName"), "Mission");
			IDictionary<string, double> dictionary = ReadStatistics(trackedValues, tracker);
			IList<MedalSnapshot> list = ReadMedals(obj2, trackedValues, maxMedals, includeConditions, maxConditionsPerMedal);
			return new StatsSnapshot(true, text, currentLanguage, dictionary, list);
		}

		private IDictionary<string, double> ReadStatistics(object trackedValues, object tracker)
		{
			Dictionary<string, double> dictionary = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);
			string[] trackedStatisticIds = TrackedStatisticIds;
			foreach (string text in trackedStatisticIds)
			{
				AddNumber(dictionary, text, _bridge.Get(trackedValues, text));
			}
			foreach (KeyValuePair<string, string> trackerMember in TrackerMembers)
			{
				AddNumber(dictionary, trackerMember.Key, _bridge.Get(tracker, trackerMember.Value));
			}
			if (!dictionary.ContainsKey("ShotsFiredAll") && dictionary.ContainsKey("ShotsFired"))
			{
				dictionary["ShotsFiredAll"] = dictionary["ShotsFired"];
			}
			AddTimeDerivatives(dictionary);
			StatsCalculator.AddDerivedValues((IDictionary<string, double>)dictionary);
			return dictionary;
		}

		private IList<MedalSnapshot> ReadMedals(object mission, object trackedValues, int maxMedals, bool includeConditions, int maxConditionsPerMedal)
		{
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			List<MedalSnapshot> list = new List<MedalSnapshot>();
			if (mission == null || trackedValues == null || maxMedals <= 0)
			{
				return list;
			}
			IList<object> list2 = _bridge.Enumerate(_bridge.Get(mission, "Medals"));
			for (int i = 0; i < list2.Count; i++)
			{
				if (list.Count >= maxMedals)
				{
					break;
				}
				object instance = list2[i];
				string text = _localization.ResolveIdentifier(_bridge.Get(instance, "displayNameV2"), "Medal " + (i + 1));
				object conditionSet = _bridge.Get(instance, "BronzeConditions");
				object conditionSet2 = _bridge.Get(instance, "SilverConditions");
				object conditionSet3 = _bridge.Get(instance, "GoldConditions");
				MedalTierSnapshot val = CreateTierSnapshot("Bronze", conditionSet, trackedValues, includeConditions, maxConditionsPerMedal);
				MedalTierSnapshot val2 = CreateTierSnapshot("Silver", conditionSet2, trackedValues, includeConditions, maxConditionsPerMedal);
				MedalTierSnapshot val3 = CreateTierSnapshot("Gold", conditionSet3, trackedValues, includeConditions, maxConditionsPerMedal);
				List<MedalTierSnapshot> list3 = new List<MedalTierSnapshot> { val, val2, val3 };
				double num = ((!val.Achieved) ? (val.Progress / 3.0) : ((!val2.Achieved) ? ((1.0 + val2.Progress) / 3.0) : ((!val3.Achieved) ? ((2.0 + val3.Progress) / 3.0) : 1.0)));
				list.Add(new MedalSnapshot(text, num, (IList<MedalTierSnapshot>)list3));
			}
			return list;
		}

		private MedalTierSnapshot CreateTierSnapshot(string tier, object conditionSet, object trackedValues, bool includeConditions, int maxConditions)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			bool flag = _bridge.Boolean(_bridge.Invoke(conditionSet, "Resolve", trackedValues));
			IList<MedalConditionSnapshot> list = ReadConditions(conditionSet, trackedValues, int.MaxValue);
			List<MedalConditionSnapshot> list2 = new List<MedalConditionSnapshot>();
			if (includeConditions)
			{
				for (int i = 0; i < list.Count && i < maxConditions; i++)
				{
					list2.Add(list[i]);
				}
			}
			return new MedalTierSnapshot(tier, flag, flag ? 1.0 : CalculateMedalProgress(list), (IList<MedalConditionSnapshot>)list2);
		}

		private IList<MedalConditionSnapshot> ReadConditions(object conditionSet, object trackedValues, int limit)
		{
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			List<MedalConditionSnapshot> list = new List<MedalConditionSnapshot>();
			IList<object> list2 = _bridge.Enumerate(_bridge.Get(conditionSet, "Conditions"));
			for (int i = 0; i < list2.Count; i++)
			{
				if (list.Count >= limit)
				{
					break;
				}
				object obj = list2[i];
				object instance = _bridge.Get(obj, "Condition") ?? obj;
				object obj2 = _bridge.Get(instance, "Left");
				object obj3 = _bridge.Get(instance, "Right");
				double num = _bridge.Number(_bridge.Invoke(obj2, "Resolve", trackedValues));
				double num2 = _bridge.Number(_bridge.Invoke(obj3, "Resolve", trackedValues));
				ExpressionInfo expressionInfo = DescribeExpression(obj2, trackedValues);
				ExpressionInfo expressionInfo2 = DescribeExpression(obj3, trackedValues);
				string text = CompareText(_bridge.Text(_bridge.Get(instance, "Operator")));
				if (expressionInfo.IsInline && !expressionInfo2.IsInline)
				{
					list.Add(new MedalConditionSnapshot(expressionInfo2.Id ?? "Value", num2, InvertComparison(text), num, expressionInfo2.InputValues));
				}
				else
				{
					list.Add(new MedalConditionSnapshot(expressionInfo.Id ?? "Value", num, text, num2, expressionInfo.InputValues));
				}
			}
			return list;
		}

		private ExpressionInfo DescribeExpression(object expression, object trackedValues)
		{
			string text = _bridge.Text(_bridge.Get(expression, "Mode"));
			if (!string.IsNullOrEmpty(text) && !text.Equals("Value", StringComparison.OrdinalIgnoreCase))
			{
				ExpressionInfo expressionInfo = DescribeOperand(_bridge.Get(expression, "A"), trackedValues);
				ExpressionInfo expressionInfo2 = DescribeOperand(_bridge.Get(expression, "B"), trackedValues);
				string text2 = MathOperatorText(_bridge.Text(_bridge.Get(expression, "MathOperator")));
				Dictionary<string, double> dictionary = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);
				MergeInputs(dictionary, expressionInfo.InputValues);
				MergeInputs(dictionary, expressionInfo2.InputValues);
				return new ExpressionInfo((expressionInfo.Id ?? "Value") + text2 + (expressionInfo2.Id ?? "Value"), isInline: false, dictionary);
			}
			string text3 = _bridge.Text(_bridge.Get(expression, "Source"));
			if (text3.Equals("Variable", StringComparison.OrdinalIgnoreCase))
			{
				string id = _bridge.Text(_bridge.Get(expression, "Variable"));
				double value = _bridge.Number(_bridge.Invoke(expression, "Resolve", trackedValues));
				return ExpressionInfo.ForStatistic(id, value);
			}
			if (text3.Equals("CustomVariable", StringComparison.OrdinalIgnoreCase))
			{
				string id2 = _bridge.Text(_bridge.Get(expression, "CustomVariableKey"));
				double value2 = _bridge.Number(_bridge.Invoke(expression, "Resolve", trackedValues));
				return ExpressionInfo.ForStatistic(id2, value2);
			}
			return new ExpressionInfo(null, isInline: true, new Dictionary<string, double>());
		}

		private ExpressionInfo DescribeOperand(object operand, object trackedValues)
		{
			string text = _bridge.Text(_bridge.Get(operand, "Source"));
			double value = _bridge.Number(_bridge.Invoke(operand, "Resolve", trackedValues));
			if (text.Equals("Variable", StringComparison.OrdinalIgnoreCase))
			{
				return ExpressionInfo.ForStatistic(_bridge.Text(_bridge.Get(operand, "Variable")), value);
			}
			if (text.Equals("CustomVariable", StringComparison.OrdinalIgnoreCase))
			{
				return ExpressionInfo.ForStatistic(_bridge.Text(_bridge.Get(operand, "CustomVariableKey")), value);
			}
			return new ExpressionInfo(value.ToString("0.##", CultureInfo.InvariantCulture), isInline: true, new Dictionary<string, double>());
		}

		private static void MergeInputs(IDictionary<string, double> target, IDictionary<string, double> source)
		{
			foreach (KeyValuePair<string, double> item in source)
			{
				target[item.Key] = item.Value;
			}
		}

		private static string MathOperatorText(string value)
		{
			return value switch
			{
				"Divide" => "/", 
				"Multiply" => "*", 
				"Subtract" => "-", 
				"Add" => "+", 
				_ => "?", 
			};
		}

		private int ResolveTier(object bronze, object silver, object gold, object trackedValues)
		{
			if (_bridge.Boolean(_bridge.Invoke(gold, "Resolve", trackedValues)))
			{
				return 3;
			}
			if (_bridge.Boolean(_bridge.Invoke(silver, "Resolve", trackedValues)))
			{
				return 2;
			}
			if (_bridge.Boolean(_bridge.Invoke(bronze, "Resolve", trackedValues)))
			{
				return 1;
			}
			return 0;
		}

		private static double CalculateMedalProgress(IList<MedalConditionSnapshot> conditions)
		{
			if (conditions == null || conditions.Count == 0)
			{
				return 0.0;
			}
			double num = 1.0;
			for (int i = 0; i < conditions.Count; i++)
			{
				num = Math.Min(num, CalculateConditionProgress(conditions[i]));
			}
			return Math.Max(0.0, Math.Min(1.0, num));
		}

		private static double CalculateConditionProgress(MedalConditionSnapshot condition)
		{
			double currentValue = condition.CurrentValue;
			double targetValue = condition.TargetValue;
			switch (condition.Comparison)
			{
			case ">":
			case ">=":
				if (currentValue >= targetValue)
				{
					return 1.0;
				}
				if (!(targetValue <= 0.0))
				{
					return currentValue / targetValue;
				}
				return 0.0;
			case "<":
			case "<=":
				if (currentValue <= targetValue)
				{
					return 1.0;
				}
				if (!(currentValue <= 0.0))
				{
					return targetValue / currentValue;
				}
				return 0.0;
			case "=":
			{
				if (Math.Abs(currentValue - targetValue) < 0.0001)
				{
					return 1.0;
				}
				double num = Math.Max(Math.Abs(currentValue), Math.Abs(targetValue));
				if (!(num <= 0.0))
				{
					return Math.Min(Math.Abs(currentValue), Math.Abs(targetValue)) / num;
				}
				return 0.0;
			}
			case "!=":
				return (Math.Abs(currentValue - targetValue) >= 0.0001) ? 1 : 0;
			default:
				return 0.0;
			}
		}

		private static bool IsMissionActive(object phase)
		{
			if (phase == null)
			{
				return false;
			}
			string text = phase.ToString();
			if (string.Equals(text, "MissionActive", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (int.TryParse(text, out var result))
			{
				return result == 2;
			}
			return false;
		}

		private void AddNumber(IDictionary<string, double> target, string id, object value)
		{
			if (value != null)
			{
				target[id] = _bridge.Number(value);
			}
		}

		private static void AddTimeDerivatives(IDictionary<string, double> values)
		{
			double num = StatsCalculator.Get(values, "MissionStartTime");
			double num2 = StatsCalculator.Get(values, "FirstShotTime");
			double num3 = StatsCalculator.Get(values, "LastTargetDestroyedTime");
			if (num2 > 0.0 && num > 0.0)
			{
				values["TimeToFirstShot"] = Math.Max(0.0, num2 - num);
			}
			if (num3 > 0.0 && num > 0.0)
			{
				values["TimeToLastTargetKill"] = Math.Max(0.0, num3 - num);
			}
			if (num3 > 0.0 && num2 > 0.0)
			{
				values["TimeFromFirstShotToLastTargetKill"] = Math.Max(0.0, num3 - num2);
			}
		}

		private static string TierName(int tier)
		{
			return tier switch
			{
				1 => "Bronze", 
				2 => "Silver", 
				3 => "Gold", 
				_ => "Unearned", 
			};
		}

		private static string CompareText(string value)
		{
			return value switch
			{
				"Equal" => "=", 
				"NotEqual" => "!=", 
				"GreaterThan" => ">", 
				"GreaterThanOrEqual" => ">=", 
				"LessThan" => "<", 
				"LessThanOrEqual" => "<=", 
				_ => value ?? "?", 
			};
		}

		private static string InvertComparison(string value)
		{
			return value switch
			{
				"<=" => ">=", 
				"<" => ">", 
				">=" => "<=", 
				">" => "<", 
				_ => value, 
			};
		}
	}
	internal sealed class ReflectionBridge
	{
		private readonly Dictionary<string, Type> _types = new Dictionary<string, Type>(StringComparer.Ordinal);

		private readonly Dictionary<string, MemberInfo> _members = new Dictionary<string, MemberInfo>(StringComparer.Ordinal);

		public Type FindType(string fullName)
		{
			if (_types.TryGetValue(fullName, out var value))
			{
				return value;
			}
			List<string> list = new List<string> { fullName };
			if (fullName.LastIndexOf('.') < 0)
			{
				list.Add("Il2Cpp." + fullName);
			}
			else
			{
				list.Add("Il2Cpp" + fullName);
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				foreach (string item in list)
				{
					Type type = assembly.GetType(item, throwOnError: false);
					if (!(type == null))
					{
						_types[fullName] = type;
						return type;
					}
				}
			}
			return null;
		}

		public object GetStatic(string typeName, string memberName)
		{
			Type type = FindType(typeName);
			if (!(type == null))
			{
				return GetValue(type, null, memberName, BindingFlags.Static);
			}
			return null;
		}

		public object Get(object instance, string memberName)
		{
			if (instance != null)
			{
				return GetValue(instance.GetType(), instance, memberName, BindingFlags.Instance);
			}
			return null;
		}

		public object Invoke(object instance, string methodName, params object[] arguments)
		{
			if (instance == null)
			{
				return null;
			}
			foreach (MethodInfo item in from method in instance.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where method.Name == methodName && method.GetParameters().Length == arguments.Length
				select method)
			{
				try
				{
					return item.Invoke(instance, AdaptArguments(item.GetParameters(), arguments));
				}
				catch (ArgumentException)
				{
				}
			}
			return null;
		}

		public IList<object> Enumerate(object collection)
		{
			List<object> list = new List<object>();
			if (collection == null)
			{
				return list;
			}
			if (collection is IEnumerable enumerable)
			{
				{
					foreach (object item in enumerable)
					{
						if (item != null)
						{
							list.Add(item);
						}
					}
					return list;
				}
			}
			object value = Get(collection, "Count") ?? Get(collection, "Length");
			int num = ToInt(value);
			for (int i = 0; i < num; i++)
			{
				object obj = Invoke(collection, "get_Item", i);
				if (obj != null)
				{
					list.Add(obj);
				}
			}
			return list;
		}

		public string Text(object value)
		{
			if (value != null)
			{
				return value.ToString();
			}
			return string.Empty;
		}

		public double Number(object value, double fallback = 0.0)
		{
			if (value == null)
			{
				return fallback;
			}
			try
			{
				return Convert.ToDouble(value);
			}
			catch
			{
				return fallback;
			}
		}

		public bool Boolean(object value, bool fallback = false)
		{
			if (value == null)
			{
				return fallback;
			}
			try
			{
				return Convert.ToBoolean(value);
			}
			catch
			{
				return fallback;
			}
		}

		public int ToInt(object value, int fallback = 0)
		{
			if (value == null)
			{
				return fallback;
			}
			try
			{
				return Convert.ToInt32(value);
			}
			catch
			{
				return fallback;
			}
		}

		private object GetValue(Type type, object instance, string memberName, BindingFlags scope)
		{
			BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.NonPublic | scope;
			string key = type.AssemblyQualifiedName + "|" + scope.ToString() + "|" + memberName;
			if (!_members.TryGetValue(key, out var value))
			{
				value = (MemberInfo)(((object)type.GetProperty(memberName, bindingAttr)) ?? ((object)type.GetField(memberName, bindingAttr)));
				_members[key] = value;
			}
			PropertyInfo propertyInfo = value as PropertyInfo;
			if (propertyInfo != null)
			{
				return propertyInfo.GetValue(instance, null);
			}
			FieldInfo fieldInfo = value as FieldInfo;
			if (!(fieldInfo == null))
			{
				return fieldInfo.GetValue(instance);
			}
			return null;
		}

		private static object[] AdaptArguments(ParameterInfo[] parameters, object[] arguments)
		{
			object[] array = new object[arguments.Length];
			for (int i = 0; i < arguments.Length; i++)
			{
				object obj = arguments[i];
				Type parameterType = parameters[i].ParameterType;
				if (obj is string && parameterType.FullName == "Il2CppSystem.String")
				{
					MethodInfo methodInfo = parameterType.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo method) => method.Name == "op_Implicit" && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(string));
					array[i] = ((methodInfo == null) ? obj : methodInfo.Invoke(null, new object[1] { obj }));
				}
				else
				{
					array[i] = obj;
				}
			}
			return array;
		}
	}
}
namespace IronNestStats.Melon.Configuration
{
	public sealed class HotkeyBinding
	{
		private readonly Key _mainKey;

		private readonly IList<Key> _modifiers;

		private HotkeyBinding(Key mainKey, IList<Key> modifiers)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			_mainKey = mainKey;
			_modifiers = modifiers;
		}

		public bool IsDown()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Keyboard current = Keyboard.current;
			if ((int)_mainKey == 0 || current == null || !((ButtonControl)current[_mainKey]).wasPressedThisFrame)
			{
				return false;
			}
			for (int i = 0; i < _modifiers.Count; i++)
			{
				if (!((ButtonControl)current[_modifiers[i]]).isPressed)
				{
					return false;
				}
			}
			return true;
		}

		public static HotkeyBinding Parse(string configured, string fallback)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Invalid comparison between Unknown and I4
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Invalid comparison between Unknown and I4
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Invalid comparison between Unknown and I4
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Invalid comparison between Unknown and I4
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Invalid comparison between Unknown and I4
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			string text = (string.IsNullOrWhiteSpace(configured) ? fallback : configured);
			List<Key> list = new List<Key>();
			Key val = (Key)0;
			string[] array = text.Split(new char[4] { '+', ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				Key result;
				if (text2.Equals("Ctrl", StringComparison.OrdinalIgnoreCase) || text2.Equals("Control", StringComparison.OrdinalIgnoreCase))
				{
					result = (Key)55;
				}
				else if (text2.Equals("Alt", StringComparison.OrdinalIgnoreCase))
				{
					result = (Key)53;
				}
				else if (text2.Equals("Shift", StringComparison.OrdinalIgnoreCase))
				{
					result = (Key)51;
				}
				else if (!Enum.TryParse<Key>(text2, ignoreCase: true, out result))
				{
					continue;
				}
				if ((int)result == 55 || (int)result == 56 || (int)result == 53 || (int)result == 54 || (int)result == 51 || (int)result == 52)
				{
					list.Add(result);
				}
				else
				{
					val = result;
				}
			}
			if ((int)val != 0 || string.Equals(text, fallback, StringComparison.OrdinalIgnoreCase))
			{
				return new HotkeyBinding(val, list);
			}
			return Parse(fallback, fallback);
		}
	}
	public sealed class ModSettings
	{
		public MelonPreferences_Entry<bool> ShowMedalsByDefault { get; }

		public MelonPreferences_Entry<bool> ShowStatsByDefault { get; }

		public MelonPreferences_Entry<string> ToggleMedals { get; }

		public MelonPreferences_Entry<string> ToggleStats { get; }

		public MelonPreferences_Entry<int> MaxMedals { get; }

		public MelonPreferences_Entry<bool> ShowMedalConditions { get; }

		public MelonPreferences_Entry<int> MaxConditionsPerMedal { get; }

		public MelonPreferences_Entry<float> MedalPanelWidth { get; }

		public MelonPreferences_Entry<float> StatsPanelWidth { get; }

		public MelonPreferences_Entry<float> PanelHeight { get; }

		public MelonPreferences_Entry<float> BackgroundOpacity { get; }

		public MelonPreferences_Entry<float> RefreshInterval { get; }

		public HotkeyBinding ToggleMedalsBinding => HotkeyBinding.Parse(ToggleMedals.Value, "F7");

		public HotkeyBinding ToggleStatsBinding => HotkeyBinding.Parse(ToggleStats.Value, "F8");

		public int MedalLimit => Math.Max(0, Math.Min(8, MaxMedals.Value));

		public int ConditionLimit => Math.Max(0, Math.Min(8, MaxConditionsPerMedal.Value));

		public float RefreshSeconds => Math.Max(0.1f, Math.Min(2f, RefreshInterval.Value));

		public float Opacity => Math.Max(0.05f, Math.Min(1f, BackgroundOpacity.Value));

		public ModSettings()
		{
			MelonPreferences_Category val = MelonPreferences.CreateCategory("MissionStats", "任务统计 / Mission Stats");
			val.SetFilePath(Path.Combine(MelonEnvironment.UserDataDirectory, "MissionStats.cfg"), true, false);
			ShowMedalsByDefault = val.CreateEntry<bool>("ShowMedalsByDefault", true, "默认显示奖章 / Show medals by default", "进入任务时显示奖章面板。 / Show the medal panel when a mission starts.", false, false, (ValueValidator)null, (string)null);
			ShowStatsByDefault = val.CreateEntry<bool>("ShowStatsByDefault", false, "默认显示详细统计 / Show statistics by default", "进入任务时显示详细统计面板。 / Show the detailed statistics panel when a mission starts.", false, false, (ValueValidator)null, (string)null);
			ToggleMedals = val.CreateEntry<string>("ToggleMedals", "F7", "奖章面板快捷键 / Medal panel hotkey", "显示或隐藏奖章面板。 / Show or hide the medal panel.", false, false, (ValueValidator)null, (string)null);
			ToggleStats = val.CreateEntry<string>("ToggleStats", "F8", "详细统计快捷键 / Statistics panel hotkey", "显示或隐藏详细统计面板。 / Show or hide the detailed statistics panel.", false, false, (ValueValidator)null, (string)null);
			MaxMedals = val.CreateEntry<int>("MaxCurrentMedals", 4, "最大奖章数量 / Maximum medals", "最多显示的当前关卡奖章数量。 / Maximum number of current-mission medals shown.", false, false, (ValueValidator)null, (string)null);
			ShowMedalConditions = val.CreateEntry<bool>("ShowConditions", true, "显示奖章条件 / Show medal conditions", "显示奖章条件及相关统计。 / Show medal conditions and their related statistics.", false, false, (ValueValidator)null, (string)null);
			MaxConditionsPerMedal = val.CreateEntry<int>("MaxConditionsPerMedal", 3, "每级最多条件数 / Maximum conditions per tier", "每个奖章等级最多读取的条件数。 / Maximum conditions read for each medal tier.", false, false, (ValueValidator)null, (string)null);
			MedalPanelWidth = val.CreateEntry<float>("MedalPanelWidth", 520f, "奖章面板最大宽度 / Maximum medal panel width", "奖章面板的最大像素宽度,实际宽度根据内容调整。 / Maximum medal panel width in pixels; actual width follows its content.", false, false, (ValueValidator)null, (string)null);
			StatsPanelWidth = val.CreateEntry<float>("StatsPanelWidth", 980f, "详细统计面板宽度 / Statistics panel width", "详细统计面板的像素宽度。 / Detailed statistics panel width in pixels.", false, false, (ValueValidator)null, (string)null);
			PanelHeight = val.CreateEntry<float>("PanelHeight", 650f, "面板最大高度 / Maximum panel height", "奖章和详细统计面板的最大像素高度。 / Maximum height of the medal and statistics panels in pixels.", false, false, (ValueValidator)null, (string)null);
			BackgroundOpacity = val.CreateEntry<float>("BackgroundOpacity", 0.78f, "背景不透明度 / Background opacity", "面板背景不透明度,范围为 0.0 到 1.0。 / Panel background opacity from 0.0 to 1.0.", false, false, (ValueValidator)null, (string)null);
			RefreshInterval = val.CreateEntry<float>("RefreshInterval", 0.2f, "刷新间隔 / Refresh interval", "统计数据刷新间隔,单位为秒。 / Statistics refresh interval in seconds.", false, false, (ValueValidator)null, (string)null);
			val.SaveToFile(false);
		}
	}
}

UserLibs/MissionStats.Core.dll

Decompiled 2 days ago
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<string, StatDefinition> ById = Definitions.ToDictionary<StatDefinition, string>((StatDefinition d) => d.Id, StringComparer.OrdinalIgnoreCase);

		public static IEnumerable<StatDefinition> 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<string, double> 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<string, double> 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<string, double> 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<string, double> InputValues { get; }

		public MedalConditionSnapshot(string statisticId, double currentValue, string comparison, double targetValue, IDictionary<string, double> inputValues)
		{
			StatisticId = statisticId ?? "Value";
			CurrentValue = currentValue;
			Comparison = comparison ?? "?";
			TargetValue = targetValue;
			InputValues = inputValues ?? new Dictionary<string, double>();
		}
	}
	public sealed class MedalSnapshot
	{
		public string Name { get; }

		public double Progress { get; }

		public IList<MedalTierSnapshot> Tiers { get; }

		public MedalSnapshot(string name, double progress, IList<MedalTierSnapshot> tiers)
		{
			Name = name ?? "Medal";
			Progress = ((progress < 0.0) ? 0.0 : ((progress > 1.0) ? 1.0 : progress));
			Tiers = tiers ?? new List<MedalTierSnapshot>();
		}
	}
	public sealed class MedalTierSnapshot
	{
		public string Tier { get; }

		public bool Achieved { get; }

		public double Progress { get; }

		public IList<MedalConditionSnapshot> Conditions { get; }

		public MedalTierSnapshot(string tier, bool achieved, double progress, IList<MedalConditionSnapshot> conditions)
		{
			Tier = tier ?? string.Empty;
			Achieved = achieved;
			Progress = ((progress < 0.0) ? 0.0 : ((progress > 1.0) ? 1.0 : progress));
			Conditions = conditions ?? new List<MedalConditionSnapshot>();
		}
	}
	public sealed class StatsSnapshot
	{
		public bool Active { get; }

		public string MissionName { get; }

		public string Language { get; }

		public IDictionary<string, double> Statistics { get; }

		public IList<MedalSnapshot> Medals { get; }

		public StatsSnapshot(bool active, string missionName, string language, IDictionary<string, double> statistics, IList<MedalSnapshot> medals)
		{
			Active = active;
			MissionName = missionName ?? string.Empty;
			Language = language ?? "English";
			Statistics = statistics ?? new Dictionary<string, double>();
			Medals = medals ?? new List<MedalSnapshot>();
		}

		public static StatsSnapshot Inactive(string language)
		{
			return new StatsSnapshot(active: false, string.Empty, language, new Dictionary<string, double>(), new List<MedalSnapshot>());
		}
	}
}
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);
			}
		}
	}
}