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);
}
}
}