Decompiled source of NOXMFD v0.72.1
plugins/NOXMFD.dll
Decompiled 11 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirage.Events; using NuclearOption; using NuclearOption.Networking; using NuclearOption.SavedMission; using Rewired; using Steamworks; using TMPro; using Unity.Collections; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NOXMFD")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("NO XMFD: live Nuclear Option telemetry (HUD + MFD)")] [assembly: AssemblyFileVersion("0.72.1.0")] [assembly: AssemblyInformationalVersion("0.72.1+0c8ea9c4d40b4e9ff13895798fdb919cf15c71c9")] [assembly: AssemblyProduct("NOXMFD")] [assembly: AssemblyTitle("NOXMFD")] [assembly: AssemblyVersion("0.72.1.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.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = 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 NOXMFD { internal class AkfTracker { internal static AkfTracker? Active; private readonly AkfTrackerLogic<PersistentID> _logic = new AkfTrackerLogic<PersistentID>(); private readonly KillLog _killLog = new KillLog(); public IReadOnlyList<AkfKillEntry> AllFeed => _logic.AllFeed; public IReadOnlyList<AkfKillEntry> PlayerFeed => _logic.PlayerFeed; public int KillsAircraft => _logic.KillsAircraft; public int KillsShip => _logic.KillsShip; public int KillsVehicle => _logic.KillsVehicle; public int KillsBuilding => _logic.KillsBuilding; public int Rank => _logic.Rank; public float FundsGained => _logic.FundsGained; public float FundsSpent => _logic.FundsSpent; internal void RecordKill(PersistentID killerID, PersistentID killedID, KillType killedType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_00c3: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) PersistentUnit val = default(PersistentUnit); if (!UnitRegistry.TryGetPersistentUnit(killedID, ref val) || val == null) { return; } PersistentUnit val2 = default(PersistentUnit); bool flag = UnitRegistry.TryGetPersistentUnit(killerID, ref val2) && val2 != null; string verb = KillTypeExtensions.GetVerb(killedType, flag); FactionHQ val3 = default(FactionHQ); GameManager.GetLocalHQ(ref val3); bool victimHostile = (Object)(object)val.GetHQ() != (Object)(object)val3; Aircraft val4 = default(Aircraft); GameManager.GetLocalAircraft(ref val4); bool killerIsPlayer = flag && (Object)(object)val4 != (Object)null && killerID == ((Unit)val4).persistentID; bool flag2 = (Object)(object)val4 != (Object)null && killedID == ((Unit)val4).persistentID; int num; if (!flag2 && (int)killedType == 3 && (Object)(object)val4 != (Object)null) { Unit unit = val.unit; Missile val5 = (Missile)(object)((unit is Missile) ? unit : null); if (val5 != null) { num = ((val5.ownerID == ((Unit)val4).persistentID) ? 1 : 0); goto IL_00bb; } } num = 0; goto IL_00bb; IL_00bb: bool victimIsPlayerOrdnance = (byte)num != 0; AkfKillEntry akfKillEntry = _logic.RecordKill(killerID, flag, (val2 != null) ? PlayerNameOverride.WithSteamName(val2.unitName) : null, val2 != null && (Object)(object)val2.GetHQ() != (Object)(object)val3, PlayerNameOverride.WithSteamName(val.unitName), victimHostile, ToKind(killedType), verb, Time.unscaledTime, killerIsPlayer, flag2, victimIsPlayerOrdnance); _killLog.Write(DateTime.Now, MissionManager.CurrentMission?.Name ?? string.Empty, akfKillEntry.Attacker, flag ? FactionName(val2) : null, akfKillEntry.Victim, FactionName(val), ToKind(killedType), akfKillEntry.Weapon); } internal void CloseLog() { _killLog.Dispose(); } private static string? FactionName(PersistentUnit unit) { FactionHQ hQ = unit.GetHQ(); if (!((Object)(object)hQ != (Object)null) || !((Object)(object)hQ.faction != (Object)null)) { return null; } return hQ.faction.factionName; } internal void RecordWeaponHit(PersistentID dealerID, PersistentID missileID) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) PersistentUnit val = default(PersistentUnit); if (UnitRegistry.TryGetPersistentUnit(missileID, ref val) && val != null) { string weaponName = (((Object)(object)val.definition != (Object)null) ? val.definition.unitName : val.unitName); _logic.RecordWeaponHit(dealerID, weaponName, Time.unscaledTime); } } internal void TickFunds() { FactionHQ val = default(FactionHQ); bool flag = GameManager.GetLocalHQ(ref val) && (Object)(object)val != (Object)null; float current = (flag ? val.factionFunds : 0f); _logic.TickFunds(flag, current); } internal void TickRank() { Player val = default(Player); _logic.SetRank(GameManager.GetLocalPlayer<Player>(ref val) ? val.PlayerRank : 0); } private static AkfKillKind ToKind(KillType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown return (int)type switch { 0 => AkfKillKind.Aircraft, 4 => AkfKillKind.Ship, 1 => AkfKillKind.Vehicle, 2 => AkfKillKind.Building, _ => AkfKillKind.Missile, }; } } internal enum AkfKillKind { Aircraft, Ship, Vehicle, Building, Missile } internal sealed class AkfTrackerLogic<TId> where TId : notnull { private readonly struct WeaponHit { public readonly string Name; public readonly float Time; public WeaponHit(string name, float time) { Name = name; Time = time; } } public const int MaxFeedLines = 50; public const float WeaponTtl = 5f; private readonly List<AkfKillEntry> _allFeed = new List<AkfKillEntry>(); private readonly List<AkfKillEntry> _playerFeed = new List<AkfKillEntry>(); private readonly Dictionary<TId, WeaponHit> _lastWeaponByAttacker = new Dictionary<TId, WeaponHit>(); private int _killsAircraft; private int _killsShip; private int _killsVehicle; private int _killsBuilding; private int _rank; private float _fundsGained; private float _fundsSpent; private float _prevFunds; private bool _fundsInit; public IReadOnlyList<AkfKillEntry> AllFeed => _allFeed; public IReadOnlyList<AkfKillEntry> PlayerFeed => _playerFeed; public int KillsAircraft => _killsAircraft; public int KillsShip => _killsShip; public int KillsVehicle => _killsVehicle; public int KillsBuilding => _killsBuilding; public int Rank => _rank; public float FundsGained => _fundsGained; public float FundsSpent => _fundsSpent; public AkfKillEntry RecordKill(TId killerId, bool hasKiller, string? killerName, bool killerHostile, string victimName, bool victimHostile, AkfKillKind killedKind, string verb, float now, bool killerIsPlayer, bool victimIsPlayer, bool victimIsPlayerOrdnance) { string weapon = null; if (hasKiller && _lastWeaponByAttacker.TryGetValue(killerId, out var value) && now - value.Time <= 5f) { weapon = value.Name; } AkfKillEntry akfKillEntry = new AkfKillEntry { Attacker = (hasKiller ? killerName : null), AttackerHostile = (hasKiller && killerHostile), Victim = victimName, VictimHostile = victimHostile, Verb = verb, Weapon = weapon }; AddCapped(_allFeed, akfKillEntry); if (killerIsPlayer) { AddCapped(_playerFeed, akfKillEntry); CountPlayerKill(killedKind); return akfKillEntry; } if (victimIsPlayer || victimIsPlayerOrdnance) { akfKillEntry.PlayerIsVictim = true; AddCapped(_playerFeed, akfKillEntry); } return akfKillEntry; } public void RecordWeaponHit(TId dealerId, string weaponName, float now) { if (!string.IsNullOrEmpty(weaponName)) { _lastWeaponByAttacker[dealerId] = new WeaponHit(weaponName, now); } } public void TickFunds(bool hasFunds, float current) { if (!hasFunds) { _fundsInit = false; return; } if (_fundsInit) { float num = current - _prevFunds; if (num > 0f) { _fundsGained += num; } else if (num < 0f) { _fundsSpent += 0f - num; } } _prevFunds = current; _fundsInit = true; } public void SetRank(int rank) { _rank = rank; } private void CountPlayerKill(AkfKillKind kind) { switch (kind) { case AkfKillKind.Aircraft: _killsAircraft++; break; case AkfKillKind.Ship: _killsShip++; break; case AkfKillKind.Vehicle: _killsVehicle++; break; case AkfKillKind.Building: _killsBuilding++; break; } } private static void AddCapped(List<AkfKillEntry> list, AkfKillEntry entry) { list.Add(entry); if (list.Count > 50) { list.RemoveAt(0); } } } internal sealed class KillLog : IDisposable { internal static string Dir = string.Empty; internal static Func<bool> Enabled = () => false; internal static Action<string>? LogWarning; internal const string Header = "time,killer,killer_faction,victim,victim_faction,type,weapon"; private StreamWriter? _writer; private bool _failed; internal void Write(DateTime localTime, string missionName, string? killer, string? killerFaction, string victim, string? victimFaction, AkfKillKind kind, string? weapon) { if (_failed || !Enabled()) { return; } try { if (_writer == null) { _writer = Open(Path.Combine(Dir, FileName(missionName, localTime))); } _writer.WriteLine(Row(localTime, killer, killerFaction, victim, victimFaction, kind, weapon)); } catch (Exception ex) { _failed = true; LogWarning?.Invoke("[NOXMFD] Kill log stopped for this mission: " + ex.Message); } } public void Dispose() { try { _writer?.Dispose(); } catch (Exception ex) { LogWarning?.Invoke("[NOXMFD] Kill log close failed: " + ex.Message); } _writer = null; } private static StreamWriter Open(string path) { Directory.CreateDirectory(Path.GetDirectoryName(path)); bool num = !File.Exists(path); StreamWriter streamWriter = new StreamWriter(path, append: true, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true)) { AutoFlush = true }; if (num) { streamWriter.WriteLine("time,killer,killer_faction,victim,victim_faction,type,weapon"); } return streamWriter; } internal static string FileName(string missionName, DateTime localTime) { StringBuilder stringBuilder = new StringBuilder("kills_").Append(localTime.ToString("yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture)); if (!string.IsNullOrWhiteSpace(missionName)) { stringBuilder.Append('_'); string text = missionName.Trim(); foreach (char c in text) { stringBuilder.Append((char.IsLetterOrDigit(c) || c == '-') ? c : '_'); } } return stringBuilder.Append(".csv").ToString(); } internal static string Row(DateTime localTime, string? killer, string? killerFaction, string victim, string? victimFaction, AkfKillKind kind, string? weapon) { return string.Join(",", localTime.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), Cell(killer), Cell(killerFaction), Cell(victim), Cell(victimFaction), kind.ToString().ToLowerInvariant(), Cell(weapon)); } internal static string Cell(string? value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } string text = value; char c = text[0]; if (c == '=' || c == '+' || c == '-' || c == '@' || c == '\t' || c == '\r') { text = "'" + text; } if (text.IndexOfAny(new char[4] { ',', '"', '\n', '\r' }) < 0) { return text; } return "\"" + text.Replace("\"", "\"\"") + "\""; } } internal class AssetCapture { private const int MapMaxDim = 4096; private const int MapJpegQuality = 85; internal const int IconsPerScan = 16; internal const string MissileIconKey = "__missilewarn"; private readonly HashSet<string> _capturedIcons = new HashSet<string>(); private readonly HashSet<string> _loggedPartLayouts = new HashSet<string>(); private readonly HashSet<string> _capturedAirframes = new HashSet<string>(); private readonly HashSet<string> _capturedWeaponIcons = new HashSet<string>(); private bool _capturedFlareIcon; private bool _capturedJammerIcon; private bool _missileIconCaptured; private bool _mapCaptured; private bool _statusDisplayReadFailureLogged; private bool _failureIndicatorReadFailureLogged; private static FieldInfo? _sdStatusDisplaysField; private static FieldInfo? _sdBackgroundField; private static FieldInfo? _sdFailureIndicatorsField; private GameObject[] _failureIndicators = Array.Empty<GameObject>(); private readonly HashSet<string> _capturedFrontal = new HashSet<string>(); private readonly Dictionary<string, List<(string name, Image img)>> _frontalMarkers = new Dictionary<string, List<(string, Image)>>(); private readonly HashSet<string> _loggedWeapons = new HashSet<string>(); private readonly HashSet<string> _capturedTgtIcons = new HashSet<string>(); private readonly HashSet<string> _capturedBdfShipIcons = new HashSet<string>(); private readonly HashSet<string> _capturedBdfLogos = new HashSet<string>(); private readonly HashSet<string> _capturedBuildingIcons = new HashSet<string>(); private readonly HashSet<string> _capturedHudCatIcons = new HashSet<string>(); private static readonly (int index, string key)[] HudCategoryIconSlots = new(int, string)[5] { (2, "AIRCRAFT"), (3, "MISSILES"), (4, "VEHICLES"), (5, "BUILDINGS"), (6, "SHIPS") }; public GameObject[] FailureIndicators => _failureIndicators; public void TryCaptureAirframe(Aircraft ac) { //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_018d: 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_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)ac.definition != (Object)null) ? ((UnitDefinition)ac.definition).unitName : null); if (string.IsNullOrEmpty(text) || _capturedAirframes.Contains(text)) { return; } StatusDisplay val = Object.FindObjectOfType<StatusDisplay>(true); if ((Object)(object)val == (Object)null) { return; } if (_sdStatusDisplaysField == null) { _sdStatusDisplaysField = typeof(StatusDisplay).GetField("statusDisplays", BindingFlags.Instance | BindingFlags.NonPublic); } if (_sdBackgroundField == null) { _sdBackgroundField = typeof(StatusDisplay).GetField("aircraftBackground", BindingFlags.Instance | BindingFlags.NonPublic); } if (_sdFailureIndicatorsField == null) { _sdFailureIndicatorsField = typeof(StatusDisplay).GetField("failureIndicators", BindingFlags.Instance | BindingFlags.NonPublic); } if (_sdStatusDisplaysField == null || _sdBackgroundField == null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)"[NOXMFD] AVN: StatusDisplay reflection fields not found — airframe capture disabled."); } _capturedAirframes.Add(text); return; } Image val2; IList list; try { object? value = _sdBackgroundField.GetValue(val); val2 = (Image)((value is Image) ? value : null); list = _sdStatusDisplaysField.GetValue(val) as IList; } catch (Exception arg) { if (!_statusDisplayReadFailureLogged) { _statusDisplayReadFailureLogged = true; ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)$"[NOXMFD] AVN: StatusDisplay read failed; airframe capture will retry: {arg}"); } } return; } if ((Object)(object)val2 == (Object)null || list == null) { return; } RectTransform rectTransform = ((Graphic)val2).rectTransform; if ((Object)(object)val2.sprite == (Object)null) { return; } Rect rect = rectTransform.rect; if (((Rect)(ref rect)).width <= 0.0001f) { return; } rect = rectTransform.rect; if (((Rect)(ref rect)).height <= 0.0001f) { return; } _capturedAirframes.Add(text); Vector3 lossyScale = ((Transform)rectTransform).lossyScale; Vector3 right = ((Transform)rectTransform).right; Vector3 up = ((Transform)rectTransform).up; Vector3 eulerAngles = ((Transform)rectTransform).eulerAngles; ManualLogSource? log3 = Plugin.Log; if (log3 != null) { string text2 = $"[NOXMFD] AVN bg lossyScale=({lossyScale.x:0.000},{lossyScale.y:0.000},{lossyScale.z:0.000}) "; rect = rectTransform.rect; object arg2 = ((Rect)(ref rect)).width; rect = rectTransform.rect; log3.LogInfo((object)(text2 + $"rectSize=({arg2:0.0},{((Rect)(ref rect)).height:0.0}) " + $"right=({right.x:0.00},{right.y:0.00},{right.z:0.00}) up=({up.x:0.00},{up.y:0.00},{up.z:0.00}) " + $"euler=({eulerAngles.x:0.0},{eulerAngles.y:0.0},{eulerAngles.z:0.0})")); } if ((Object)(object)val2.sprite != (Object)null) { string bgKey = text; SpriteCapture.Request(val2.sprite, SpriteCapture.Encoding.Png, synthAlpha: false, 0, 0, delegate(byte[]? bgPng) { if (bgPng != null) { TelemetryServer.SetAirframeImage(bgKey, "__bg", bgPng); } }); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{\"type\":\"").Append(JsonLite.EscapeJson(text)).Append("\",\"parts\":["); int num = 0; int num2 = 0; for (int num3 = 0; num3 < list.Count; num3++) { object? obj = list[num3]; PartStatusDisplay val3 = (PartStatusDisplay)((obj is PartStatusDisplay) ? obj : null); if (val3 == null || (Object)(object)val3.partImage == (Object)null) { continue; } Image partImage = val3.partImage; string text3 = (((Object)(object)((Component)partImage).gameObject != (Object)null) ? ((Object)((Component)partImage).gameObject).name : null); if (string.IsNullOrEmpty(text3) || !GetPartPlacement(((Graphic)partImage).rectTransform, rectTransform, out var cx, out var cy, out var w, out var h, out var rotZ, out var sx, out var sy) || (w >= 0.98f && h >= 0.98f && Mathf.Abs(cx - 0.5f) < 0.02f && Mathf.Abs(cy - 0.5f) < 0.02f)) { continue; } if ((Object)(object)partImage.sprite != (Object)null) { string partKey = text; string partName = text3; SpriteCapture.Request(partImage.sprite, SpriteCapture.Encoding.Png, synthAlpha: false, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetAirframeImage(partKey, partName, png); } }); } if (num > 0) { stringBuilder.Append(','); } num++; if (sx < 0 || sy < 0) { num2++; } stringBuilder.Append('{').Append("\"n\":\"").Append(JsonLite.EscapeJson(text3)) .Append("\",") .Append("\"cx\":") .Append(cx.ToString("0.00000", CultureInfo.InvariantCulture)) .Append(',') .Append("\"cy\":") .Append(cy.ToString("0.00000", CultureInfo.InvariantCulture)) .Append(',') .Append("\"w\":") .Append(w.ToString("0.00000", CultureInfo.InvariantCulture)) .Append(',') .Append("\"h\":") .Append(h.ToString("0.00000", CultureInfo.InvariantCulture)) .Append(',') .Append("\"r\":") .Append(rotZ.ToString("0.0", CultureInfo.InvariantCulture)) .Append(',') .Append("\"sx\":") .Append(sx) .Append(',') .Append("\"sy\":") .Append(sy) .Append(',') .Append("\"rt\":") .Append(val3.redStatusThreshold.ToString("0.0", CultureInfo.InvariantCulture)) .Append('}'); } stringBuilder.Append("]}"); TelemetryServer.SetAirframeLayout(text, stringBuilder.ToString()); List<GameObject> list2 = new List<GameObject>(); IList list3 = null; try { list3 = _sdFailureIndicatorsField?.GetValue(val) as IList; } catch (Exception arg3) { if (!_failureIndicatorReadFailureLogged) { _failureIndicatorReadFailureLogged = true; ManualLogSource? log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)$"[NOXMFD] AVN: failure-indicator read failed: {arg3}"); } } } if (list3 != null) { for (int num4 = 0; num4 < list3.Count; num4++) { object? obj2 = list3[num4]; GameObject val4 = (GameObject)((obj2 is GameObject) ? obj2 : null); if ((Object)(object)val4 != (Object)null) { list2.Add(val4); } } } _failureIndicators = list2.ToArray(); ManualLogSource? log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)string.Format("[NOXMFD] Captured airframe silhouette '{0}' (bg + {1} parts, {2} flipped, {3} failure messages: {4}).", text, num, num2, _failureIndicators.Length, string.Join(", ", _failureIndicators.Select((GameObject g) => ((Object)g).name)))); } } private static bool GetPartPlacement(RectTransform partRT, RectTransform bgRT, out float cx, out float cy, out float w, out float h, out float rotZ, out int sx, out int sy) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) cx = (cy = (w = (h = (rotZ = 0f)))); sx = (sy = 1); if ((Object)(object)partRT == (Object)null || (Object)(object)bgRT == (Object)null) { return false; } Rect rect = bgRT.rect; if (((Rect)(ref rect)).width <= 0.0001f || ((Rect)(ref rect)).height <= 0.0001f) { return false; } Rect rect2 = partRT.rect; Vector3 val = ((Transform)partRT).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect2)).center)); Vector3 val2 = ((Transform)bgRT).InverseTransformPoint(val); cx = (val2.x - ((Rect)(ref rect)).xMin) / ((Rect)(ref rect)).width; cy = (val2.y - ((Rect)(ref rect)).yMin) / ((Rect)(ref rect)).height; cy = 1f - cy; if (((Transform)bgRT).right.x < 0f) { cx = 1f - cx; } if (((Transform)bgRT).up.y < 0f) { cy = 1f - cy; } float num = ((((Transform)bgRT).lossyScale.x == 0f) ? 1f : Mathf.Abs(((Transform)bgRT).lossyScale.x)); float num2 = ((((Transform)bgRT).lossyScale.y == 0f) ? 1f : Mathf.Abs(((Transform)bgRT).lossyScale.y)); float num3 = Mathf.Abs(((Transform)partRT).lossyScale.x); float num4 = Mathf.Abs(((Transform)partRT).lossyScale.y); rect2 = partRT.rect; w = ((Rect)(ref rect2)).width * (num3 / num) / ((Rect)(ref rect)).width; rect2 = partRT.rect; h = ((Rect)(ref rect2)).height * (num4 / num2) / ((Rect)(ref rect)).height; rotZ = ((Transform)partRT).localEulerAngles.z; if (rotZ > 180f) { rotZ -= 360f; } float x = ((Transform)partRT).lossyScale.x; float y = ((Transform)partRT).lossyScale.y; float x2 = ((Transform)bgRT).lossyScale.x; float y2 = ((Transform)bgRT).lossyScale.y; sx = ((x == 0f || x2 == 0f) ? 1 : ((!(x * x2 < 0f)) ? 1 : (-1))); sy = ((y == 0f || y2 == 0f) ? 1 : ((!(y * y2 < 0f)) ? 1 : (-1))); return true; } public void TryCaptureFrontalSilhouette(Aircraft ac) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)ac.definition != (Object)null) ? ((UnitDefinition)ac.definition).unitName : null); if (string.IsNullOrEmpty(text) || _capturedFrontal.Contains(text)) { return; } Image val = null; Image[] array = Resources.FindObjectsOfTypeAll<Image>(); foreach (Image val2 in array) { if (!((Object)(object)val2 == (Object)null) && !(((Object)((Component)val2).gameObject).name != "frontProfile")) { Scene scene = ((Component)val2).gameObject.scene; if (((Scene)(ref scene)).name != null) { val = val2; break; } } } if ((Object)(object)val == (Object)null || (Object)(object)val.sprite == (Object)null) { return; } _capturedFrontal.Add(text); string bgKey = text; SpriteCapture.Request(val.sprite, SpriteCapture.Encoding.Png, synthAlpha: false, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetAirframeImage(bgKey, "__front", png); } }); RectTransform rectTransform = ((Graphic)val).rectTransform; List<(string, Image)> list = new List<(string, Image)>(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{\"parts\":["); int num = 0; for (int num2 = 0; num2 < ((Transform)rectTransform).childCount; num2++) { Transform child = ((Transform)rectTransform).GetChild(num2); if (!((Object)child).name.StartsWith("hardpoint", StringComparison.OrdinalIgnoreCase)) { continue; } Image component = ((Component)child).GetComponent<Image>(); if (!((Object)(object)component == (Object)null) && GetPartPlacement(((Graphic)component).rectTransform, rectTransform, out var cx, out var cy, out var w, out var h, out var _, out var _, out var _)) { list.Add((((Object)child).name, component)); if (num > 0) { stringBuilder.Append(','); } num++; stringBuilder.Append('{').Append("\"n\":\"").Append(JsonLite.EscapeJson(((Object)child).name)) .Append("\",") .Append("\"cx\":") .Append(cx.ToString("0.00000", CultureInfo.InvariantCulture)) .Append(',') .Append("\"cy\":") .Append(cy.ToString("0.00000", CultureInfo.InvariantCulture)) .Append(',') .Append("\"w\":") .Append(w.ToString("0.00000", CultureInfo.InvariantCulture)) .Append(',') .Append("\"h\":") .Append(h.ToString("0.00000", CultureInfo.InvariantCulture)) .Append('}'); } } stringBuilder.Append("]}"); _frontalMarkers[text] = list; TelemetryServer.SetAirframeLayout(text + "__front", stringBuilder.ToString()); } public List<(string name, string state)> ReadFrontalMarkerStates(string? type) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0068: Unknown result type (might be due to invalid IL or missing references) List<(string, string)> list = new List<(string, string)>(); if (string.IsNullOrEmpty(type) || !_frontalMarkers.TryGetValue(type, out List<(string, Image)> value)) { return list; } foreach (var (item, val) in value) { if (!((Object)(object)val == (Object)null)) { Color color = ((Graphic)val).color; string item2 = ((color.r == color.g && color.g == color.b) ? "empty" : ((color.g >= color.r) ? "armed" : "exhausted")); list.Add((item, item2)); } } return list; } public void TryLogPartLayout(Aircraft ac) { string text = (((Object)(object)ac.definition != (Object)null) ? ((UnitDefinition)ac.definition).unitName : null); if (string.IsNullOrEmpty(text) || _loggedPartLayouts.Contains(text)) { return; } List<UnitPart> partLookup = ((Unit)ac).partLookup; if (partLookup == null) { return; } _loggedPartLayouts.Add(text); ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[NOXMFD] AVN parts for '{text}' (count={partLookup.Count}):"); } for (int i = 0; i < partLookup.Count; i++) { UnitPart val = partLookup[i]; if ((Object)(object)val == (Object)null) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$" [{i}] <null>"); } continue; } string text2 = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : "<no-go>"); ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$" [{i}] {text2} hp={val.hitPoints:0.#} detached={val.IsDetached()}"); } } } public void TryLogWeaponInfo(Aircraft ac) { List<WeaponStation> weaponStations = ((Unit)ac).weaponStations; if (weaponStations == null) { return; } foreach (WeaponStation item in weaponStations) { WeaponInfo val = item?.WeaponInfo; if ((Object)(object)val == (Object)null) { continue; } string text = ((!string.IsNullOrEmpty(((Object)val).name)) ? ((Object)val).name : ((!string.IsNullOrEmpty(val.weaponName)) ? val.weaponName : (val.shortName ?? "?"))); if (!_loggedWeapons.Contains(text)) { _loggedWeapons.Add(text); ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] Weapon '" + text + "' name=\"" + val.weaponName + "\" short=\"" + val.shortName + "\" " + $"flags[gun={val.gun} missile={val.missile} bomb={val.bomb} glideBomb={val.glideBomb} " + $"jammer={val.jammer} energy={val.energy} nuclear={val.nuclear} strategic={val.strategic} " + $"overHorizon={val.overHorizon} laserGuided={val.laserGuided} boresight={val.boresight} " + $"cargo={val.cargo} troops={val.troops} sling={val.sling} " + $"rearmGround={val.rearmGround} rearmShip={val.rearmShip} hideInDisplay={val.hideInDisplay}] " + $"role[antiSurface={val.effectiveness.antiSurface:0.##} antiAir={val.effectiveness.antiAir:0.##} " + $"antiMissile={val.effectiveness.antiMissile:0.##} antiRadar={val.effectiveness.antiRadar:0.##}] " + $"pK={val.pK:0.###} fireInterval={val.fireInterval:0.###} muzzleVelocity={val.muzzleVelocity:0.#} " + $"maxSpeed={val.maxSpeed:0.#} dragCoef={val.dragCoef:0.###} gravMult={val.gravMult:0.##} " + $"pierceDamage={val.pierceDamage:0.#} blastDamage={val.blastDamage:0.#} " + $"armorTierEffectiveness={val.armorTierEffectiveness:0.##} airburstHeight={val.airburstHeight:0.#} " + $"visibilityWhenFired={val.visibilityWhenFired:0.##} costPerRound={val.costPerRound:0.#} " + $"massPerRound={val.massPerRound:0.##} useWeaponDoors={val.useWeaponDoors} " + $"hasIcon={(Object)(object)val.weaponIcon != (Object)null}")); } } } } public void TryCaptureCmIcons(Aircraft ac) { if (!_capturedFlareIcon) { FlareEjector componentInChildren = ((Component)ac).GetComponentInChildren<FlareEjector>(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)((Countermeasure)componentInChildren).displayImage != (Object)null) { _capturedFlareIcon = true; SpriteCapture.Request(((Countermeasure)componentInChildren).displayImage, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetCmIcon("flares", png); } }); } } if (_capturedJammerIcon) { return; } RadarJammer componentInChildren2 = ((Component)ac).GetComponentInChildren<RadarJammer>(); if (!((Object)(object)componentInChildren2 != (Object)null) || !((Object)(object)((Countermeasure)componentInChildren2).displayImage != (Object)null)) { return; } _capturedJammerIcon = true; SpriteCapture.Request(((Countermeasure)componentInChildren2).displayImage, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetCmIcon("jammer", png); } }); } public void TryCaptureVehicleTypeIcons() { Encyclopedia i = Encyclopedia.i; if (!((Object)(object)i == (Object)null)) { CaptureTypeIcons(i.vehicleTypes, _capturedTgtIcons, (UnitType vt) => vt.typeName, (UnitType vt) => vt.typeSprite, TelemetryServer.SetTgtIcon); } } public void TryCaptureShipTypeIcons() { Encyclopedia i = Encyclopedia.i; if (!((Object)(object)i == (Object)null)) { CaptureTypeIcons(i.shipTypes, _capturedBdfShipIcons, (UnitType st) => st.typeName, (UnitType st) => st.typeSprite, TelemetryServer.SetBdfIcon); } } public void TryCaptureFactionLogo(FactionHQ hq) { Faction val = (((Object)(object)hq != (Object)null) ? hq.faction : null); if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.factionName)) { return; } string name = val.factionName; if (_capturedBdfLogos.Contains(name)) { return; } _capturedBdfLogos.Add(name); if ((Object)(object)val.factionColorLogo == (Object)null) { return; } SpriteCapture.Request(val.factionColorLogo, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetBdfIcon(name, png); } }); } public void TryCaptureBuildingTypeIcons() { Encyclopedia i = Encyclopedia.i; if (!((Object)(object)i == (Object)null)) { CaptureTypeIcons(i.buildingTypes, _capturedBuildingIcons, (UnitType bt) => bt.typeName, (UnitType bt) => bt.typeSprite, TelemetryServer.SetBuildingIcon); } } private static void CaptureTypeIcons<T>(IEnumerable<T> list, HashSet<string> captured, Func<T, string> nameOf, Func<T, Sprite> spriteOf, Action<string, byte[]> setIcon) where T : class { if (list == null) { return; } foreach (T item in list) { if (item == null) { continue; } string name = nameOf(item); if (string.IsNullOrEmpty(name) || captured.Contains(name)) { continue; } captured.Add(name); Sprite val = spriteOf(item); if ((Object)(object)val == (Object)null) { continue; } SpriteCapture.Request(val, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { if (png != null) { setIcon(name, png); } }); } } public void TryCaptureHudCategoryIcons() { HUDOptions i = SceneSingleton<HUDOptions>.i; if ((Object)(object)i == (Object)null || i.listCategories == null) { return; } (int, string)[] hudCategoryIconSlots = HudCategoryIconSlots; for (int j = 0; j < hudCategoryIconSlots.Length; j++) { (int, string) tuple = hudCategoryIconSlots[j]; if (_capturedHudCatIcons.Contains(tuple.Item2) || tuple.Item1 >= i.listCategories.Count) { continue; } HUDOptions_Category val = i.listCategories[tuple.Item1]; if ((Object)(object)val == (Object)null) { continue; } Transform val2 = ((Component)val).transform.Find("TopContainer/Icon"); Image val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<Image>() : null); if ((Object)(object)val3 == (Object)null || (Object)(object)val3.sprite == (Object)null) { continue; } _capturedHudCatIcons.Add(tuple.Item2); string key = tuple.Item2; SpriteCapture.Request(val3.sprite, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetHudCategoryIcon(key, png); } }); } } public void TryCaptureWeaponIcon(string name, Sprite icon) { if (string.IsNullOrEmpty(name) || _capturedWeaponIcons.Contains(name)) { return; } _capturedWeaponIcons.Add(name); if ((Object)(object)icon == (Object)null) { return; } string weaponName = name; SpriteCapture.Request(icon, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetWeaponIcon(weaponName, png); } }); } public void TryCaptureMap(MapSettings ms) { if (_mapCaptured) { return; } Sprite mapImage = ms.MapImage; if (!((Object)(object)mapImage == (Object)null)) { _mapCaptured = true; Texture texture = (Texture)(object)mapImage.texture; int sw = (((Object)(object)texture != (Object)null) ? texture.width : 0); int sh = (((Object)(object)texture != (Object)null) ? texture.height : 0); if (!SpriteCapture.Request(mapImage, SpriteCapture.Encoding.Jpg, synthAlpha: false, 85, 4096, delegate(byte[]? jpg) { if (jpg != null) { TelemetryServer.SetMapImage(jpg); ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[NOXMFD] Captured in-game map ({jpg.Length} bytes, JPEG; source {sw}x{sh})."); } } else { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[NOXMFD] Map capture failed; falling back to map file."); } } })) { _mapCaptured = false; } } } public void CaptureMissileWarningIcon() { if (_missileIconCaptured) { return; } try { GameAssets i = GameAssets.i; if ((Object)(object)i == (Object)null || (Object)(object)i.missileWarningSprite == (Object)null) { return; } _missileIconCaptured = true; SpriteCapture.Request(i.missileWarningSprite, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { if (png != null) { TelemetryServer.SetIcon("__missilewarn", png); } }); } catch { } } public bool TryCaptureIcon(UnitDefinition def) { if ((Object)(object)def == (Object)null || string.IsNullOrEmpty(def.unitName) || _capturedIcons.Contains(def.unitName)) { return false; } _capturedIcons.Add(def.unitName); if ((Object)(object)def.mapIcon == (Object)null) { TelemetryServer.SetIcon(def.unitName, TelemetryServer.NoIconPng); return false; } string name = def.unitName; bool num = SpriteCapture.Request(def.mapIcon, SpriteCapture.Encoding.Png, synthAlpha: true, 0, 0, delegate(byte[]? png) { TelemetryServer.SetIcon(name, png ?? TelemetryServer.NoIconPng); }); if (!num) { TelemetryServer.SetIcon(name, TelemetryServer.NoIconPng); } return num; } } internal static class SpriteCapture { internal enum Encoding { Png, Jpg } private const GraphicsFormat Fmt = (GraphicsFormat)4; public static bool Request(Sprite sprite, Encoding enc, bool synthAlpha, int quality, int maxDim, Action<byte[]?> onEncoded) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_015f: 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_0124: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null) { return false; } Texture2D texture = sprite.texture; Rect textureRect = sprite.textureRect; int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width); int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height); if (num <= 0 || num2 <= 0) { num = ((Texture)texture).width; num2 = ((Texture)texture).height; ((Rect)(ref textureRect))..ctor(0f, 0f, (float)num, (float)num2); } var (tw, th) = TgpFeedSettings.FitWithinMaxDimension(num, num2, maxDim); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height); if (SystemInfo.supportsAsyncGPUReadback) { RenderTexture rt = new RenderTexture(tw, th, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); rt.Create(); Graphics.Blit((Texture)(object)texture, rt, val, val2); AsyncGPUReadback.Request((Texture)(object)rt, 0, (GraphicsFormat)4, (Action<AsyncGPUReadbackRequest>)delegate(AsyncGPUReadbackRequest req) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnReadback(req, rt, tw, th, enc, synthAlpha, quality, onEncoded); }); return true; } return RequestSync(texture, val, val2, tw, th, enc, synthAlpha, quality, onEncoded); } private static void OnReadback(AsyncGPUReadbackRequest req, RenderTexture rt, int w, int h, Encoding enc, bool synthAlpha, int quality, Action<byte[]?> onEncoded) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) try { if (((AsyncGPUReadbackRequest)(ref req)).hasError) { Deliver(onEncoded, null); return; } NativeArray<byte> data = ((AsyncGPUReadbackRequest)(ref req)).GetData<byte>(0); byte[] bytes = new byte[data.Length]; data.CopyTo(bytes); Task.Run(delegate { EncodeAndDeliver(bytes, w, h, enc, synthAlpha, quality, onEncoded); }); } catch (Exception ex) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)("[NOXMFD] SpriteCapture readback failed: " + ex.Message)); } Deliver(onEncoded, null); } finally { rt.Release(); Object.Destroy((Object)(object)rt); } } private static bool RequestSync(Texture2D tex, Vector2 scale, Vector2 offset, int w, int h, Encoding enc, bool synthAlpha, int quality, Action<byte[]?> onEncoded) { //IL_0016: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) RenderTexture temporary = RenderTexture.GetTemporary(w, h, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); Texture2D val = null; RenderTexture active = RenderTexture.active; try { Graphics.Blit((Texture)(object)tex, temporary, scale, offset); RenderTexture.active = temporary; val = new Texture2D(w, h, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)w, (float)h), 0, 0); val.Apply(); EncodeAndDeliver(val.GetRawTextureData(), w, h, enc, synthAlpha, quality, onEncoded); return true; } catch (Exception ex) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)("[NOXMFD] SpriteCapture (sync) failed: " + ex.Message)); } Deliver(onEncoded, null); return false; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } RenderTexture.ReleaseTemporary(temporary); } } private static void EncodeAndDeliver(byte[] rgba, int w, int h, Encoding enc, bool synthAlpha, int quality, Action<byte[]?> onEncoded) { try { if (synthAlpha) { SynthesizeAlphaIfOpaque(rgba); } byte[] bytes = ((enc == Encoding.Jpg) ? ImageConversion.EncodeArrayToJPG((Array)rgba, (GraphicsFormat)4, (uint)w, (uint)h, 0u, quality) : ImageConversion.EncodeArrayToPNG((Array)rgba, (GraphicsFormat)4, (uint)w, (uint)h, 0u)); Deliver(onEncoded, bytes); } catch (Exception ex) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)("[NOXMFD] SpriteCapture encode failed: " + ex.Message)); } Deliver(onEncoded, null); } } private static void Deliver(Action<byte[]?> onEncoded, byte[]? bytes) { try { onEncoded(bytes); } catch (Exception arg) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[NOXMFD] SpriteCapture consumer failed: {arg}"); } } } private static void SynthesizeAlphaIfOpaque(byte[] px) { byte b = byte.MaxValue; for (int i = 3; i < px.Length; i += 4) { if (px[i] < b) { b = px[i]; if (b == 0) { return; } } } if (b >= 250) { for (int j = 0; j < px.Length; j += 4) { int num = px[j]; int num2 = px[j + 1]; int num3 = px[j + 2]; px[j + 3] = (byte)(num * 77 + num2 * 150 + num3 * 29 >> 8); } } } } internal static class CmReflection { private static FieldInfo? _stationsField; private static MethodInfo? _getFirstMethod; private static bool _loggedStationsFailure; private static bool _loggedCountermeasureFailure; public static IList? GetStations(CountermeasureManager mgr) { if (_stationsField == null) { _stationsField = typeof(CountermeasureManager).GetField("countermeasureStations", BindingFlags.Instance | BindingFlags.NonPublic); } try { return _stationsField?.GetValue(mgr) as IList; } catch (Exception arg) { if (!_loggedStationsFailure) { _loggedStationsFailure = true; ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[NOXMFD] countermeasure GetFirstCountermeasure invocation failed; CM integration is unavailable: {arg}"); } } return null; } } public static Countermeasure? GetFirstCountermeasure(object station) { if (_getFirstMethod == null) { _getFirstMethod = station.GetType().GetMethod("GetFirstCountermeasure", BindingFlags.Instance | BindingFlags.Public); } try { object? obj = _getFirstMethod?.Invoke(station, null); return (Countermeasure?)((obj is Countermeasure) ? obj : null); } catch (Exception arg) { if (!_loggedCountermeasureFailure) { _loggedCountermeasureFailure = true; ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[NOXMFD] countermeasure station read failed; CM integration is unavailable: {arg}"); } } return null; } } } [Serializable] internal class CommandEnvelope { public string? cmd; public long id; public string? wname; public string? group; public int index; public bool on; public string? bind; public string? key; public string? cid; public int n; public float hz; public float x; public float y; public string peer; public string name; public string type; public string payload; public float wx; public float wz; public string? text; } internal static class CommandDispatcher { private static readonly Dictionary<string, Action<CommandEnvelope>> _handlers = new Dictionary<string, Action<CommandEnvelope>>(StringComparer.Ordinal) { { "target.select", TargetSelect }, { "target.deselect", TargetDeselect }, { "weapon.select", WeaponSelect }, { "weapon.cycle", WeaponCycle }, { "weapon.deploy-cargo", WeaponDeployCargo }, { "cm.deploy", CountermeasureDeploy }, { "gear.set", GearSet }, { "tgt.set", TgtSet }, { "tgt.only", TgtOnly }, { "tgt.reset", TgtReset }, { "tgt.clear", TgtClear }, { "tgt.clear-datalink", TgtClearDatalink }, { "tgt.clear-stale", TgtClearStale }, { "tgt.sort", TgtSort }, { "tgt.laser", TgtLaser }, { "tgt.hud", TgtHud }, { "hud.set", HudSet }, { "hud.mode", HudMode }, { "declutter.set", DeclutterSet }, { "avn.toggle", AvnToggle }, { "avn.set", AvnSet }, { "diag.log", DiagLog }, { "rates.set", delegate(CommandEnvelope e) { if (e.group == "tgp") { RatesConfig.SetTgpHz(e.hz); } else if (e.group == "contact") { RatesConfig.SetContactHz(e.hz); } else if (e.group == "tgpResolution" || e.group == "tgpQuality") { RatesConfig.SetTgpResolution(e.wname ?? "native"); } else if (e.group == "tgpJpegQuality") { RatesConfig.SetTgpJpegQuality(e.wname ?? "mid"); } else if (e.group == "tgpSuppressNative") { RatesConfig.SetTgpSuppressNative(e.wname == "on" || e.on); } else if (e.group == "mapShowPlayerNames") { RatesConfig.SetMapShowPlayerNames(e.wname == "on" || e.on); } else { RatesConfig.SetFastHz(e.hz); } } }, { "master-arms.set", delegate(CommandEnvelope e) { ImmersionState.MasterArmsOn = e.on; } }, { "power.set", delegate(CommandEnvelope e) { ImmersionState.PowerOn = e.on; } }, { "sqd.create", delegate(CommandEnvelope e) { Squad.CreateSquad(e.name ?? string.Empty, e.index); } }, { "sqd.invite", delegate(CommandEnvelope e) { if (TryPeer(e.peer, out var id)) { Squad.Invite(id, e.name ?? string.Empty); } } }, { "sqd.set-callsign", delegate(CommandEnvelope e) { Squad.SetCallsign(e.name ?? string.Empty, e.index); } }, { "sqd.accept", delegate(CommandEnvelope e) { if (TryPeer(e.peer, out var id)) { Squad.AcceptInvite(id); } } }, { "sqd.decline", delegate(CommandEnvelope e) { if (TryPeer(e.peer, out var id)) { Squad.DeclineInvite(id); } } }, { "sqd.leave", delegate { Squad.Leave(); } }, { "sqd.relinquish", delegate(CommandEnvelope e) { Squad.RelinquishLeadership(TryPeer(e.peer, out var id) ? new ulong?(id) : ((ulong?)null)); } }, { "sqd.disband", delegate { Squad.Disband(); } }, { "sqd.kick", delegate(CommandEnvelope e) { if (TryPeer(e.peer, out var id)) { Squad.Kick(id); } } }, { "sqd.set-self-callsign", delegate(CommandEnvelope e) { Squad.SetSelfCallsign(e.name ?? string.Empty, e.index, e.n); } }, { "sqd.clear-self-callsign", delegate { Squad.ClearSelfCallsign(); } }, { "sqd.send", delegate(CommandEnvelope e) { Squad.SendData(e.type, e.payload); } }, { "td.cell", delegate(CommandEnvelope e) { if (Squad.IsLeader && TryPeer(e.peer, out var id) && Squad.AllMemberIds().Contains(id)) { TdStore.ToggleCell((uint)e.id, id); } } }, { "td.row", delegate(CommandEnvelope e) { if (Squad.IsLeader) { TdStore.ToggleRow((uint)e.id, Squad.AllMemberIds()); } } }, { "td.column", delegate(CommandEnvelope e) { if (Squad.IsLeader && TryPeer(e.peer, out var id) && Squad.AllMemberIds().Contains(id)) { TdStore.ToggleColumn(id, ParseIds(e.text)); } } }, { "td.clear", delegate { if (Squad.IsLeader) { TdStore.ClearOwn(); } } }, { "td.designate", TdDesignate }, { "td.accept", delegate(CommandEnvelope e) { TdAccept(e.on); } }, { "td.dismiss", delegate { TdStore.ClearDesignated(); } }, { "tgp.ir.set", delegate(CommandEnvelope e) { TgpManualControl.SetIR(e.on); } }, { "tgp.view.set", delegate(CommandEnvelope e) { TgpSingleTargetView.SetStv(e.on); } }, { "tgp.manual-toggle", delegate { TgpManualControl.Toggle(); } }, { "tgp.ir-toggle", delegate { TgpManualControl.ToggleIR(); } }, { "tgp.view-toggle", delegate { TgpSingleTargetView.ToggleStv(); } }, { "tgp.snap-headtracker", delegate { TgpManualControl.SnapToHeadTracker(); } }, { "tgp.fullscreen-toggle", delegate { TgpFullScreen.Toggle(); } }, { "tgp.fullscreen-hud-toggle", delegate { TgpFullScreen.ToggleHud(); } }, { "internal-mfd.poc-toggle", delegate { InternalMfdController.Toggle(); } }, { "units.toggle", delegate { Keybinds.ToggleUnits(); } }, { "hsd.set-view", delegate(CommandEnvelope e) { HsdViewState.Set(e.on, e.index); } }, { "tgp.mark-steerpoint", delegate { TgpManualControl.MarkSteerPoint(); } }, { "tgp.point-track", delegate { TgpManualControl.TogglePointTrack(); } }, { "tgp.manual-reset", delegate { TgpManualControl.Reset(); } }, { "tgp.slew", delegate(CommandEnvelope e) { TgpManualControl.SlewTo(e.wx, e.wz); } }, { "tgp.zoom.step", delegate(CommandEnvelope e) { if (TgpManualControl.ManualMode) { TgpManualControl.StepZoom(e.index); } else { TgpLockZoom.StepZoom(e.index); } } }, { "tgp.zoom.set", delegate(CommandEnvelope e) { TgpManualControl.SetZoom(e.index, e.on); } }, { "combat-mode.set", delegate(CommandEnvelope e) { string text = e.group; CombatMode combatMode = ((text == "aa") ? CombatMode.AirToAir : ((text == "ag") ? CombatMode.AirToGround : CombatMode.All)); Keybinds.SetCombatMode(combatMode); } }, { "keybind.set-key", delegate(CommandEnvelope e) { Log("set-key", e.bind, Keybinds.SetKeyBind(e.bind ?? string.Empty, e.key ?? string.Empty, e.on)); } }, { "keybind.arm-joy", delegate(CommandEnvelope e) { Log("arm-joy", e.bind, Keybinds.ArmJoyCapture(e.bind ?? string.Empty, e.on)); } }, { "keybind.resolve", delegate(CommandEnvelope e) { Log("resolve", e.bind, Keybinds.ResolveConflict(e.group ?? string.Empty)); } }, { "keybind.cancel-joy", delegate { Keybinds.CancelJoyCapture(); } }, { "keybind.clear-joy", delegate(CommandEnvelope e) { Log("clear-joy", e.bind, Keybinds.ClearJoyBind(e.bind ?? string.Empty)); } }, { "keybind.arm-axis", delegate(CommandEnvelope e) { Log("arm-axis", e.bind, Keybinds.ArmAxisCapture(e.bind ?? string.Empty)); } }, { "keybind.cancel-axis", delegate { Keybinds.CancelAxisCapture(); } }, { "keybind.clear-axis", delegate(CommandEnvelope e) { Log("clear-axis", e.bind, Keybinds.ClearAxisBind(e.bind ?? string.Empty)); } }, { "keybind.set-axis-invert", delegate(CommandEnvelope e) { Log("set-axis-invert", e.bind, Keybinds.SetAxisInvert(e.bind ?? string.Empty, e.on)); } }, { "keybind.set-bg-input", delegate(CommandEnvelope e) { Keybinds.SetBackgroundInput(e.on); } }, { "keybind.set-radar-on-start", delegate(CommandEnvelope e) { ImmersionConfig.SetRadarOnOnStart(e.on); } }, { "keybind.set-engine-on-start", delegate(CommandEnvelope e) { ImmersionConfig.SetEngineOnOnStart(e.on); } }, { "keybind.set-master-arms-on-start", delegate(CommandEnvelope e) { ImmersionConfig.SetMasterArmsOnOnStart(e.on); } }, { "keybind.set-power-on-start", delegate(CommandEnvelope e) { ImmersionConfig.SetPowerOnOnStart(e.on); } }, { "keybind.set-hud-filters-on-combat-mode", delegate(CommandEnvelope e) { ImmersionConfig.SetHudFiltersOnCombatMode(e.on); } }, { "soi.next", delegate { TelemetryServer.SoiCycle(1); } }, { "soi.prev", delegate { TelemetryServer.SoiCycle(-1); } }, { "soi.action", delegate(CommandEnvelope e) { TelemetryServer.SoiAction(e.wname ?? string.Empty); } }, { "map.action", MapAction }, { "cursor.select", delegate { TelemetryServer.CursorSelect(); } }, { "cursor.set", CursorSet }, { "fire.set", FireSet }, { "soi.panes", delegate(CommandEnvelope e) { TelemetryServer.SetPaneCount(e.cid ?? string.Empty, e.n); } }, { "soi.page", delegate(CommandEnvelope e) { TelemetryServer.ReportSoiPage(e.cid ?? string.Empty, e.n, e.wname ?? string.Empty); } }, { "soi.include", delegate(CommandEnvelope e) { TelemetryServer.SetSoiIncluded(e.cid ?? string.Empty, e.n, e.on); } }, { "wpt.create", delegate(CommandEnvelope e) { LogWpt("create", RouteStore.CreateRoute(e.wname ?? string.Empty) != null); } }, { "wpt.rename", delegate(CommandEnvelope e) { LogWpt("rename", RouteStore.RenameRoute(e.bind ?? string.Empty, e.wname ?? string.Empty)); } }, { "wpt.delete", delegate(CommandEnvelope e) { LogWpt("delete", RouteStore.DeleteRoute(e.bind ?? string.Empty)); } }, { "wpt.set-active", delegate(CommandEnvelope e) { RouteStore.SetActiveRoute(e.bind ?? string.Empty); } }, { "wpt.clear", delegate { RouteStore.ClearRoutes(); } }, { "wpt.reset-route", delegate(CommandEnvelope e) { LogWpt("reset-route", RouteStore.ResetRoute(e.bind ?? string.Empty)); } }, { "wpt.import", delegate(CommandEnvelope e) { LogWpt("import", RouteStore.ImportRoute(e.text ?? string.Empty)); } }, { "wpt.rename-waypoint", delegate(CommandEnvelope e) { LogWpt("rename-waypoint", RouteStore.RenameWaypoint(e.index, e.wname ?? string.Empty, e.bind)); } }, { "wpt.reorder-waypoint", delegate(CommandEnvelope e) { LogWpt("reorder-waypoint", RouteStore.ReorderWaypoint(e.index, e.n, e.bind)); } }, { "wpt.reset-waypoint", delegate(CommandEnvelope e) { LogWpt("reset-waypoint", RouteStore.ResetWaypoint(e.index)); } }, { "wpt.remove-waypoint", delegate(CommandEnvelope e) { LogWpt("remove-waypoint", RouteStore.RemoveWaypoint(e.index, e.bind)); } }, { "wpt.cycle-route", delegate(CommandEnvelope e) { RouteStore.CycleActiveRoute(e.index); } }, { "wpt.step-waypoint", delegate(CommandEnvelope e) { RouteStore.StepWaypoint(e.index); } }, { "wpt.step-navigation", delegate(CommandEnvelope e) { RouteStore.StepNavigation(e.index); } }, { "wpt.add-waypoint", delegate(CommandEnvelope e) { RouteStore.AddWaypoint(e.wx, e.wz, e.wname ?? string.Empty); } }, { "wpt.add-navigation-point", delegate(CommandEnvelope e) { RouteStore.AddNavigationPoint(e.wx, e.wz, e.wname ?? string.Empty); } }, { "wpt.add-steerpoint", delegate(CommandEnvelope e) { RouteStore.AddSteerPoint(e.wx, e.wz, e.wname ?? string.Empty); } }, { "wpt.rename-steerpoint", delegate(CommandEnvelope e) { LogWpt("rename-steerpoint", RouteStore.RenameSteerPoint(e.bind ?? string.Empty, e.wname ?? string.Empty)); } }, { "wpt.delete-steerpoint", delegate(CommandEnvelope e) { LogWpt("delete-steerpoint", RouteStore.DeleteSteerPoint(e.bind ?? string.Empty)); } }, { "wpt.set-active-steerpoint", delegate(CommandEnvelope e) { RouteStore.SetActiveSteerPoint(e.bind ?? string.Empty); } }, { "wpt.cycle-steerpoint", delegate(CommandEnvelope e) { RouteStore.CycleSteerPoint(e.index); } }, { "wpt.import-steerpoints", delegate(CommandEnvelope e) { LogWpt("import-steerpoints", RouteStore.ImportSteerPoints(e.text ?? string.Empty)); } }, { "wpt.accept-shared", delegate(CommandEnvelope e) { LogWpt("accept-shared", RouteStore.AcceptShared(e.bind)); } }, { "wpt.reject-shared", delegate(CommandEnvelope e) { LogWpt("reject-shared", RouteStore.RejectShared(e.bind)); } }, { "wpt.share", delegate(CommandEnvelope e) { LogWpt("share", RouteStore.ShareRoute(e.bind)); } }, { "wpt.accept-shared-steerpoint", delegate(CommandEnvelope e) { LogWpt("accept-shared-steerpoint", RouteStore.AcceptSharedSteerPoint(e.bind ?? string.Empty)); } }, { "wpt.reject-shared-steerpoint", delegate(CommandEnvelope e) { LogWpt("reject-shared-steerpoint", RouteStore.RejectSharedSteerPoint(e.bind ?? string.Empty)); } }, { "wpt.share-steerpoint", delegate(CommandEnvelope e) { LogWpt("share-steerpoint", RouteStore.ShareSteerPoint(e.bind ?? string.Empty)); } }, { "layout.save", delegate(CommandEnvelope e) { LogLayout("save", LayoutStore.SaveLayout(e.wname ?? string.Empty, e.group ?? string.Empty, e.text ?? string.Empty)); } }, { "layout.update", delegate(CommandEnvelope e) { LogLayout("update", LayoutStore.UpdateLayout(e.bind ?? string.Empty, e.wname ?? string.Empty, e.text ?? string.Empty)); } }, { "layout.rename", delegate(CommandEnvelope e) { LogLayout("rename", LayoutStore.RenameLayout(e.bind ?? string.Empty, e.wname ?? string.Empty)); } }, { "layout.delete", delegate(CommandEnvelope e) { LogLayout("delete", LayoutStore.DeleteLayout(e.bind ?? string.Empty)); } }, { "theme.create", delegate(CommandEnvelope e) { LogTheme("create", ThemeStore.Create(e.wname, e.bind)); } }, { "theme.rename", delegate(CommandEnvelope e) { LogTheme("rename", ThemeStore.Rename(e.bind, e.wname)); } }, { "theme.delete", delegate(CommandEnvelope e) { LogTheme("delete", ThemeStore.Delete(e.bind)); } }, { "theme.select", delegate(CommandEnvelope e) { LogTheme("select", ThemeStore.Select(e.bind)); } }, { "theme.set-color", delegate(CommandEnvelope e) { LogTheme("set-color", ThemeStore.SetColor(e.group, e.text)); } }, { "theme.reset-color", delegate(CommandEnvelope e) { LogTheme("reset-color", ThemeStore.ResetColor(e.group)); } }, { "theme.import", delegate(CommandEnvelope e) { LogTheme("import", ThemeStore.Import(e.text)); } }, { "theme.rescan", delegate { LogTheme("rescan", ThemeStore.Rescan()); } }, { "preset.save", delegate(CommandEnvelope e) { LogPreset("save", HudPresetStore.Save(e.wname ?? string.Empty, e.index)); } }, { "preset.rename", delegate(CommandEnvelope e) { LogPreset("rename", HudPresetStore.Rename(e.index, e.wname ?? string.Empty)); } }, { "preset.delete", delegate(CommandEnvelope e) { LogPreset("delete", HudPresetStore.Delete(e.index)); } }, { "preset.load", delegate(CommandEnvelope e) { LogPreset("load", HudPresetStore.LoadPreset(e.index)); } }, { "tgt-preset.save", delegate(CommandEnvelope e) { LogTgtPreset("save", TgtPresetStore.Save(e.wname ?? string.Empty, e.index)); } }, { "tgt-preset.rename", delegate(CommandEnvelope e) { LogTgtPreset("rename", TgtPresetStore.Rename(e.index, e.wname ?? string.Empty)); } }, { "tgt-preset.delete", delegate(CommandEnvelope e) { LogTgtPreset("delete", TgtPresetStore.Delete(e.index)); } }, { "tgt-preset.load", delegate(CommandEnvelope e) { LogTgtPreset("load", TgtPresetStore.LoadPreset(e.index)); } } }; private static void Log(string op, string? bind, bool ok) { if (!ok) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] keybind." + op + " '" + bind + "': rejected.")); } } } private static bool TryPeer(string s, out ulong id) { id = 0uL; if (string.IsNullOrWhiteSpace(s)) { return false; } if (!ulong.TryParse(s.Trim(), NumberStyles.None, CultureInfo.InvariantCulture, out id) || id == 0L) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] squadron: rejected peer id '" + s + "'.")); } return false; } return true; } private static void LogWpt(string op, bool ok) { if (!ok) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] wpt." + op + ": rejected.")); } } } private static void LogLayout(string op, bool ok) { if (!ok) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] layout." + op + ": rejected.")); } } } private static void LogTheme(string op, bool ok) { if (!ok) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] theme." + op + ": rejected.")); } } } private static void LogPreset(string op, bool ok) { if (!ok) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] preset." + op + ": rejected.")); } } } private static void LogTgtPreset(string op, bool ok) { if (!ok) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] tgt-preset." + op + ": rejected.")); } } } public static bool IsKnown(string cmd) { if (cmd != null) { return _handlers.ContainsKey(cmd); } return false; } public static void Drain() { CommandEnvelope env; while (CommandEndpoint.TryDequeueCommand(out env)) { if (env == null) { continue; } if (_handlers.TryGetValue(env.cmd ?? string.Empty, out Action<CommandEnvelope> value)) { try { value(env); } catch (Exception arg) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[NOXMFD] command '{env.cmd}' (group '{env.group}') threw: {arg}"); } } } else { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[NOXMFD] unknown command '" + env.cmd + "' — dropped.")); } } } } private static void TargetSelect(CommandEnvelope env) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) uint num = (uint)env.id; if (num == 0) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] target.select: id=0 (missing/unparsed) — ignored."); } return; } Unit val = default(Unit); if (!UnitRegistry.TryGetUnit((PersistentID?)new PersistentID { Id = num }, ref val) || (Object)(object)val == (Object)null || val.disabled) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] target.select id={num}: no live unit (stale) — ignored."); } return; } Aircraft val2 = default(Aircraft); GameManager.GetLocalAircraft(ref val2); if ((Object)(object)val2 == (Object)null || (Object)(object)((Unit)val2).NetworkHQ == (Object)null) { ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[NOXMFD] target.select id={num}: no local aircraft/HQ — ignored."); } } else if (!IsDetectedByPlayer(val2, val)) { ManualLogSource? log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[NOXMFD] target.select id={num}: not visible to player — ignored."); } } else { TrySelectTarget(val, "target.select"); } } internal static bool IsDetectedByPlayer(Aircraft ac, Unit unit) { GlobalPosition val = default(GlobalPosition); bool factionKnown = ((Unit)ac).NetworkHQ.TryGetKnownPosition(unit, ref val); TargetDetector radar = ((Unit)ac).radar; bool ownRadarDetected = ((radar is Radar) ? radar : null)?.detectedTargets.Contains(unit) ?? false; CombatHUD i = SceneSingleton<CombatHUD>.i; bool pictureJamActive = (Object)(object)i != (Object)null && i.jamAccumulation > 0f; return TargetSelectionPolicy.IsSelectable(factionKnown, ownRadarDetected, pictureJamActive); } internal static bool TrySelectTarget(Unit unit, string source) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)unit == (Object)null || unit.disabled) { return false; } Aircraft val = default(Aircraft); GameManager.GetLocalAircraft(ref val); if ((Object)(object)val == (Object)null || (Object)(object)val.weaponManager == (Object)null) { return false; } if ((object)unit == val) { return false; } string text = unit.definition?.unitName ?? "?"; if ((int)DynamicMap.GetFactionMode(unit.NetworkHQ, false) == 0) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[NOXMFD] {source} '{text}' (id={unit.persistentID.Id}): no-faction unit — ignored."); } return false; } TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i != (Object)null && i.CheckExclusions(unit)) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] {source} '{text}' (id={unit.persistentID.Id}): excluded by TGT filters — ignored."); } return false; } WeaponManager weaponManager = val.weaponManager; if (weaponManager.CheckIsTarget(unit)) { ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[NOXMFD] {source} '{text}' (id={unit.persistentID.Id}): already targeted — no-op."); } return false; } CombatHUD i2 = SceneSingleton<CombatHUD>.i; bool flag = (Object)(object)i2 != (Object)null && i2.aircraft == val && i2.MarkerExists(unit); if ((Object)(object)i2 != (Object)null && flag) { i2.SelectUnit(unit); } else { weaponManager.AddTargetList(unit); } ManualLogSource? log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[NOXMFD] {source} → '{text}' (id={unit.persistentID.Id}, viaHud={flag})."); } return true; } private static void TargetDeselect(CommandEnvelope env) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) uint num = (uint)env.id; if (num == 0) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] target.deselect: id=0 (missing/unparsed) — ignored."); } return; } Unit val = default(Unit); if (!UnitRegistry.TryGetUnit((PersistentID?)new PersistentID { Id = num }, ref val) || (Object)(object)val == (Object)null) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] target.deselect id={num}: no such unit — ignored."); } return; } Aircraft val2 = default(Aircraft); GameManager.GetLocalAircraft(ref val2); if ((Object)(object)val2 == (Object)null || (Object)(object)val2.weaponManager == (Object)null) { return; } WeaponManager weaponManager = val2.weaponManager; string arg = val.definition?.unitName ?? "?"; if (!weaponManager.CheckIsTarget(val)) { ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[NOXMFD] target.deselect '{arg}' (id={num}): not targeted — no-op."); } return; } if (TargetFocus.Id == num) { TargetFocus.Cycle(1, TelemetryReader.TargetIds(weaponManager.GetTargetList())); } CombatHUD i = SceneSingleton<CombatHUD>.i; bool flag = (Object)(object)i != (Object)null && i.aircraft == val2 && i.MarkerExists(val); if ((Object)(object)i != (Object)null && flag) { i.DeSelectUnit(val); } else { weaponManager.RemoveTargetList(val); } ManualLogSource? log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[NOXMFD] target.deselect ← '{arg}' (id={num}, viaHud={flag})."); } } private static void WeaponSelect(CommandEnvelope env) { string text = env.wname ?? string.Empty; if (string.IsNullOrEmpty(text)) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] weapon.select: empty name — ignored."); } return; } Aircraft val = default(Aircraft); GameManager.GetLocalAircraft(ref val); if ((Object)(object)val == (Object)null || (Object)(object)val.weaponManager == (Object)null || ((Unit)val).weaponStations == null) { return; } WeaponManager weaponManager = val.weaponManager; WeaponStation val2 = WeaponSelectors.FindStationByName(val, text); if (val2 == null) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[NOXMFD] weapon.select '" + text + "': no matching station — ignored.")); } return; } if (weaponManager.currentWeaponStation == val2) { ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[NOXMFD] weapon.select '" + text + "': already selected — no-op.")); } return; } WeaponSelectors.SelectStation(val, val2); ManualLogSource? log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[NOXMFD] weapon.select → '{text}' (station {val2.Number})."); } } private static bool LocalAircraft(string op, out Aircraft ac) { GameManager.GetLocalAircraft(ref ac); if ((Object)(object)ac == (Object)null || ((Unit)ac).disabled) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] " + op + ": no local aircraft — ignored.")); } return false; } return true; } private static void WeaponCycle(CommandEnvelope env) { if (!LocalAircraft("weapon.cycle", out Aircraft ac)) { return; } switch (env.group) { case "guns": WeaponSelectors.CycleGun(ac); return; case "missiles": WeaponSelectors.CycleMissile(ac); return; case "bombs": WeaponSelectors.CycleBomb(ac); return; case "cargo": WeaponSelectors.CycleCargo(ac); return; } ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] weapon.cycle: unknown group '" + env.group + "' — ignored.")); } } private static void WeaponDeployCargo(CommandEnvelope env) { if (LocalAircraft("weapon.deploy-cargo", out Aircraft ac)) { WeaponSelectors.DeployCargo(ac); } } private static void CountermeasureDeploy(CommandEnvelope env) { if (!LocalAircraft("cm.deploy", out Aircraft ac)) { return; } string text = env.group; if (!(text == "flares")) { if (text == "jammer") { Keybinds.DriveCountermeasure(ac, 2); return; } ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] cm.deploy: unknown group '" + env.group + "' — ignored.")); } } else { Keybinds.DriveCountermeasure(ac, 1); } } private static void GearSet(CommandEnvelope env) { if (!LocalAircraft("gear.set", out Aircraft ac)) { return; } string text = env.group; if (!(text == "up")) { if (text == "down") { Keybinds.DriveGear(ac, up: false, down: true); return; } ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] gear.set: unknown group '" + env.group + "' — ignored.")); } } else { Keybinds.DriveGear(ac, up: true, down: false); } } private static void CursorSet(CommandEnvelope env) { TelemetryServer.SetRemoteCursorState(ClampUnit(env.x), ClampUnit(env.y), env.on); } private static void FireSet(CommandEnvelope env) { TelemetryServer.SetRemoteFireState(env.group ?? string.Empty, env.on); } private static void MapAction(CommandEnvelope env) { string text = env.wname ?? string.Empty; TelemetryServer.MapAction(text); switch (text) { case "tgt-next": Keybinds.CycleTargetFocus(1); break; case "tgt-prev": Keybinds.CycleTargetFocus(-1); break; case "tgt-datalink": ClearDatalinkTargets(); break; case "tgt-stale": ClearStaleTargets(); break; } } private static float ClampUnit(float value) { if (value < -1f) { return -1f; } if (value > 1f) { return 1f; } return value; } private static List<TargetListSelector_ToggleButton>? TgtGroup(TargetListSelector sel, string? group) { return group switch { "faction" => sel.toggleFactionItems, "category" => sel.toggleUnitTypesItems, "vehicle" => sel.toggleVehicleTypesItems, _ => null, }; } private static TargetListSelector_ToggleButton? TgtResolve(CommandEnvelope env, string op, out TargetListSelector sel) { sel = null; TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] " + op + ": TargetListSelector absent — ignored.")); } return null; } sel = i; List<TargetListSelector_ToggleButton> list = TgtGroup(sel, env.group); if (list == null) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[NOXMFD] " + op + ": unknown group '" + env.group + "' — ignored.")); } return null; } if (env.index < 0 || env.index >= list.Count) { ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[NOXMFD] {op}: index {env.index} out of range for '{env.group}' [{list.Count}] — ignored."); } return null; } TargetListSelector_ToggleButton val = list[env.index]; if ((Object)(object)val == (Object)null) { ManualLogSource? log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[NOXMFD] {op}: null toggle at {env.group}[{env.index}] — ignored."); } return null; } return val; } private static void TgtSet(CommandEnvelope env) { TargetListSelector sel; TargetListSelector_ToggleButton val = TgtResolve(env, "tgt.set", out sel); if (!((Object)(object)val == (Object)null) && val.status != env.on) { val.Set(env.on); ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[NOXMFD] tgt.set {env.group}[{env.index}] = {env.on}."); } } } private static void TgtOnly(CommandEnvelope env) { TargetListSelector sel; TargetListSelector_ToggleButton val = TgtResolve(env, "tgt.only", out sel); if (!((Object)(object)val == (Object)null)) { sel.SetOnlyItem(val); ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[NOXMFD] tgt.only {env.group}[{env.index}]."); } } } private static void TgtReset(CommandEnvelope env) { TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] tgt.reset: TargetListSelector absent — ignored."); } return; } i.ResetFilters(); ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[NOXMFD] tgt.reset — all filters on."); } } private static void TgtClear(CommandEnvelope env) { TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] tgt.clear: TargetListSelector absent — ignored."); } return; } i.DeselectAll(); ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[NOXMFD] tgt.clear — deselected all targets."); } } private static bool IsDatalinkOnly(FactionHQ playerHQ, Unit unit) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)unit == (Object)null || (Object)(object)unit.NetworkHQ == (Object)(object)playerHQ) { return false; } TrackingInfo trackingData = playerHQ.GetTrackingData(unit.persistentID); return trackingData == null || !trackingData.Observed(); } private static bool IsStale(FactionHQ playerHQ, Unit unit) { if ((Object)(object)unit == (Object)null || (Object)(object)unit.NetworkHQ == (Object)(object)playerHQ) { return false; } return !playerHQ.IsTargetPositionAccurate(unit, 20f); } private static void TgtClearBy(string op, Func<FactionHQ, Unit, bool> predicate) { TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] " + op + ": TargetListSelector absent — ignored.")); } return; } Aircraft val = default(Aircraft); GameManager.GetLocalAircraft(ref val); if ((Object)(object)val == (Object)null || (Object)(object)val.weaponManager == (Object)null || (Object)(object)((Unit)val).NetworkHQ == (Object)null) { return; } FactionHQ networkHQ = ((Unit)val).NetworkHQ; List<Unit> targetList = val.weaponManager.GetTargetList(); if (targetList == null || targetList.Count == 0) { return; } int num = 0; foreach (Unit item in new List<Unit>(targetList)) { if (predicate(networkHQ, item)) { i.ForceDeselect(item); num++; } } ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] {op} — deselected {num} target(s)."); } } private static void TgtClearDatalink(CommandEnvelope env) { ClearDatalinkTargets(); } private static void TgtClearStale(CommandEnvelope env) { ClearStaleTargets(); } private static void TgtSort(CommandEnvelope env) { if (!TargetSort.Set(env.key ?? "", env.index)) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] tgt.sort: unknown key '" + env.key + "' — ignored.")); } } } internal static void ClearDatalinkTargets() { TgtClearBy("tgt.clear-datalink", IsDatalinkOnly); } internal static void ClearStaleTargets() { TgtClearBy("tgt.clear-stale", IsStale); } private static void TdAccept(bool replace) { //IL_0066: 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) if (TdStore.Designated.Count == 0) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] td.accept: nothing pending — ignored."); } return; } if (replace) { TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i == (Object)null) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[NOXMFD] td.accept: TargetListSelector absent — ignored."); } return; } i.DeselectAll(); } int num = 0; Unit val = default(Unit); foreach (TdStore.Row item in TdStore.Designated) { if (UnitRegistry.TryGetUnit((PersistentID?)new PersistentID { Id = item.Id }, ref val) && (Object)(object)val != (Object)null && !val.disabled && TrySelectTarget(val, "td.accept")) { num++; } } TdStore.AcceptDesignated(); ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)string.Format("[NOXMFD] td.accept ({0}) — selected {1} target(s).", replace ? "replace" : "add", num)); } } private static List<uint> ParseIds(string? json) { List<uint> list = new List<uint>(); if (JsonLite.Parse(json ?? "[]") is List<object> list2) { foreach (object item in list2) { if (item is double num && num > 0.0) { list.Add((uint)num); } } } return list; } private static void TdDesignate(CommandEnvelope e) { if (!Squad.IsLeader) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] td.designate: not the squad leader — ignored."); } return; } if (!TryPeer(e.peer, out var id)) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[NOXMFD] td.designate: missing/unparsed peer — ignored."); } return; } List<uint> list = new List<uint>(); if (JsonLite.Parse(e.text ?? "[]") is List<object> list2) { foreach (object item in list2) { if (item is Dictionary<string, object> dictionary && dictionary.TryGetValue("id", out var value) && value is double num) { list.Add((uint)num); } } } bool flag = Squad.SendDataTo(id, "td.designate", e.text ?? "[]"); if (flag) { TdStore.MarkSent(id, list); } ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)(flag ? $"[NOXMFD] td.designate → {id}: sent {list.Count} target(s)." : $"[NOXMFD] td.designate → {id}: not sent — not a current squad member, or the Steam send itself failed.")); } } private static void TgtLaser(CommandEnvelope env) { TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i == (Object)null || (Object)(object)i.toggleLaser == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] tgt.laser: unavailable — ignored."); } } else if (i.toggleLaser.status != env.on) { i.toggleLaser.Set(env.on); ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] tgt.laser = {env.on}."); } } } private static void TgtHud(CommandEnvelope env) { TargetListSelector i = SceneSingleton<TargetListSelector>.i; if ((Object)(object)i == (Object)null || (Object)(object)i.toggleFollowHUD == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] tgt.hud: unavailable — ignored."); } } else if (i.toggleFollowHUD.status != env.on) { i.toggleFollowHUD.Set(env.on); ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] tgt.hud = {env.on}."); } } } private static void HudSet(CommandEnvelope env) { HUDOptions i = SceneSingleton<HUDOptions>.i; if ((Object)(object)i == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] hud.set: HUDOptions unavailable — ignored."); } return; } switch (env.group) { case "category": { if (!InList(i.listCategories, env.index, "hud.set category")) { return; } HUDOptions_Category val3 = i.listCategories[env.index]; if ((Object)(object)val3 == (Object)null || val3.maximized == env.on) { return; } val3.Set(env.on); break; } case "vehicle": { if (!InList(i.listVehicleTypes, env.index, "hud.set vehicle")) { return; } HUDOptions_ToggleButton val = i.listVehicleTypes[env.index]; if ((Object)(object)val == (Object)null || val.status == env.on) { return; } val.Set(env.on); break; } case "building": { if (!InList(i.listBuildingTypes, env.index, "hud.set building")) { return; } HUDOptions_ToggleButton val2 = i.listBuildingTypes[env.index]; if ((Object)(object)val2 == (Object)null || val2.status == env.on) { return; } val2.Set(env.on); break; } default: { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[NOXMFD] hud.set: unknown group '" + env.group + "' — ignored.")); } return; } } i.ApplyHUDSettings(); HudCombatModeFilters.CaptureIfIdle(); ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[NOXMFD] hud.set {env.group}[{env.index}] = {env.on}."); } } private static void HudMode(CommandEnvelope env) { HUDOptions i = SceneSingleton<HUDOptions>.i; if ((Object)(object)i == (Object)null) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NOXMFD] hud.mode: HUDOptions unavailable — ignored."); } } else { if (!InList(i.listModes, env.index, "hud.mode")) { return; } HUDOptions_ToggleButton val = i.listModes[env.index]; if ((Object)(object)val == (Object)null) { ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] hud.mode[{env.index}] is null — ignored."); } return; } i.ToggleButtons(val); i.ApplyHUDSettings(); HudCombatModeFilters.CaptureIfIdle(); ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[NOXMFD] hud.mode = {env.index}."); } } } private static void DeclutterSet(CommandEnvelope env) { switch (env.group) { case "weapon": HudDeclutterConfig.SetHideWeaponAmmo(env.on); break; case "minimap": HudDeclutterConfig.SetHideMinimap(env.on); break; case "boxes": HudDeclutterConfig.SetHideTopBoxes(env.on); break; case "feed": HudDeclutterConfig.SetHideKillFeed(env.on); break; default: { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] declutter.set: unknown group '" + env.group + "' — ignored.")); } return; } } ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] declutter.set {env.group} hide={env.on}."); } } private static void AvnToggle(CommandEnvelope env) { Aircraft val = default(Aircraft); GameManager.GetLocalAircraft(ref val); if ((Object)(object)val == (Object)null || ((Unit)val).disabled) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[NOXMFD] DIAG98 avn.toggle {env.group}: no live aircraft (null={(Object)(object)val == (Object)null}) — ignored."); } return; } ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] DIAG98 avn.toggle {env.group} before: radarAlt={((Unit)val).radarAlt:0.00} {TelemetryReader.Diag98State(val)}"); } switch (env.group) { case "gear": Keybinds.DriveGear(val, up: true, down: true); break; case "radar": val.CmdToggleRadar(); break; case "guns": { WeaponManager weaponManager = val.weaponManager; if (weaponManager != null) { weaponManager.ToggleGunsLinked(); } break; } case "eng": val.CmdToggleIgnition(); break; case "assist": val.TogglePitchLimiter(); break; case "nvg": NightVision.Toggle(); break; case "lights": val.ToggleNavLights(); break; case "turret": { CombatHUD i = SceneSingleton<CombatHUD>.i; if (i != null) { i.ToggleAutoControl(); } break; } default: { ManualLogSource? log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[NOXMFD] avn.toggle: unknown group '" + env.group + "' — ignored.")); } return; } } ManualLogSource? log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)("[NOXMFD] avn.toggle " + env.group + ".")); } ManualLogSource? log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)("[NOXMFD] DIAG98 avn.toggle " + env.group + " after: " + TelemetryReader.Diag98State(val))); } } private static void DiagLog(CommandEnvelope env) { string text = env.group ?? ""; if (text.Length > 200) { text = text.Substring(0, 200); } ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] DIAG98 web: " + text)); } } private static void AvnSet(CommandEnvelope env) { if (!LocalAircraft("avn.set", out Aircraft ac)) { return; } string text = env.group; if (!(text == "radar")) { if (!(text == "eng")) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)("[NOXMFD] avn.set: unknown group '" + env.group + "' — ignored.")); } return; } Keybinds.SetEngine(ac, env.on); } else { Keybinds.SetRadar(ac, env.on); } ManualLogSource? log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[NOXMFD] avn.set {env.group} = {env.on}."); } } private static bool InList<T>(List<T> list, int index, string who) { if (list == null || index < 0 || index >= list.Count) { ManualLogSource? log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[NOXMFD] {who}: index {index} out of range — ignored."); } return false; } return true; } } internal static class ConfigBackup { internal static Action<string>? LogWarning; private static readonly HashSet<string> _warnedPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static void BackupIfExists(string path) { try { if (File.Exists(path)) { File.Copy(path, path + ".bak", overwrite: true); } } catch (IOException ex) { WarnOnce(path, ex); } catch (UnauthorizedAccessException ex2) { WarnOnce(path, ex2); } } private static void WarnOnce(string path, Exception ex) { lock (_warnedPaths) { if (!_warnedPaths.Add(path)) { return; } } LogWarning?.Invoke("[NOXMFD] could not back up '" + path + "': " + ex.Message + "; saving will continue."); } } internal sealed class ConfigurationManagerAttributes { public bool? Browsable; } public static class Api { public delegate byte[]? AssetResolver(string relPath); public delegate void CommandHandler(string json); public const int ApiVersion = 7; public static int RouteRevision =>