using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using NuclearOption.Chat;
using NuclearOption.Networking;
using NuclearOption.SavedMission.ObjectiveV2;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GlassPanel")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.8.0.0")]
[assembly: AssemblyInformationalVersion("1.8.0+71ddbeaf6d5dc173f4b567b92a2464a23ce7d1c1")]
[assembly: AssemblyProduct("NO Glass Panel")]
[assembly: AssemblyTitle("GlassPanel")]
[assembly: AssemblyVersion("1.8.0.0")]
namespace GlassPanel;
internal static class ChatBridge
{
private struct Line
{
public string who;
public string msg;
}
private static readonly List<Line> _lines = new List<Line>();
private static readonly object _lock = new object();
private const int MAX = 40;
public static void Add(string who, string msg)
{
if (string.IsNullOrEmpty(msg))
{
return;
}
lock (_lock)
{
_lines.Add(new Line
{
who = (who ?? ""),
msg = msg
});
if (_lines.Count > 40)
{
_lines.RemoveAt(0);
}
}
}
public static string BuildJson()
{
lock (_lock)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < _lines.Count; i++)
{
if (i > 0)
{
stringBuilder.Append(',');
}
stringBuilder.Append("{\"who\":\"").Append(Esc(_lines[i].who)).Append("\",\"msg\":\"")
.Append(Esc(_lines[i].msg))
.Append("\"}");
}
return stringBuilder.ToString();
}
}
private static string Esc(string s)
{
if (s != null)
{
return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
}
return "";
}
public static void Send(string text, bool allChat)
{
try
{
if (!string.IsNullOrEmpty(text) && ChatManager.CanSend(text, false, false))
{
ChatManager.SendChatMessage(text, allChat);
}
}
catch
{
}
}
}
[HarmonyPatch(typeof(ChatManager), "UserCode_TargetReceiveMessage_1307761090")]
internal static class Patch_ReceiveMessage
{
private static void Postfix(string message, Player player, bool allChat)
{
string who = "?";
try
{
if ((Object)(object)player != (Object)null)
{
who = player.PlayerName;
}
}
catch
{
}
ChatBridge.Add(who, message);
}
}
[HarmonyPatch(typeof(ChatManager), "UserCode_RpcServerMessage_1244201393")]
internal static class Patch_ServerMessage
{
private static void Postfix(string message)
{
ChatBridge.Add("SERVER", message);
}
}
[HarmonyPatch(typeof(WeaponIndicator), "Show")]
internal static class Patch_HideWeaponIndicator
{
private static void Prefix(ref bool arg)
{
if (Plugin.HideWeaponHMD)
{
arg = false;
}
}
}
internal class MiniServer
{
private const string WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private readonly int _port;
private readonly byte[] _pageBytes;
private readonly List<Socket> _clients = new List<Socket>();
private readonly object _lock = new object();
private Socket _listen;
private Thread _acceptThread;
private volatile bool _running;
public Action<string> OnMessage;
public int ClientCount
{
get
{
lock (_lock)
{
return _clients.Count;
}
}
}
public MiniServer(int port, string pageHtml)
{
_port = port;
_pageBytes = Encoding.UTF8.GetBytes(pageHtml ?? "");
}
public void Start()
{
try
{
_running = true;
_listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listen.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true);
_listen.Bind(new IPEndPoint(IPAddress.Any, _port));
_listen.Listen(16);
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogInfo((object)("MiniServer LISTENING on " + _listen.LocalEndPoint));
}
_acceptThread = new Thread(AcceptLoop)
{
IsBackground = true,
Name = "GlassPanel-accept"
};
_acceptThread.Start();
}
catch (Exception ex)
{
ManualLogSource log2 = Plugin.Log;
if (log2 != null)
{
log2.LogError((object)("MiniServer bind FAILED: " + ex));
}
}
}
public void Stop()
{
_running = false;
try
{
_listen?.Close();
}
catch
{
}
lock (_lock)
{
foreach (Socket client in _clients)
{
try
{
client.Close();
}
catch
{
}
}
_clients.Clear();
}
}
private void AcceptLoop()
{
while (_running)
{
Socket socket = null;
try
{
socket = _listen.Accept();
}
catch
{
if (!_running)
{
break;
}
Thread.Sleep(50);
continue;
}
try
{
Handle(socket);
}
catch (Exception ex)
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogWarning((object)("client handle error: " + ex.Message));
}
try
{
socket.Close();
}
catch
{
}
}
}
}
private void Handle(Socket sock)
{
string text;
using (NetworkStream stream = new NetworkStream(sock, ownsSocket: false))
{
text = ReadHeaders(stream);
}
if (text == null)
{
sock.Close();
}
else if (text.IndexOf("upgrade: websocket", StringComparison.OrdinalIgnoreCase) >= 0)
{
string text2 = ExtractHeader(text, "sec-websocket-key");
if (text2 == null)
{
sock.Close();
return;
}
string text3;
using (SHA1 sHA = SHA1.Create())
{
text3 = Convert.ToBase64String(sHA.ComputeHash(Encoding.UTF8.GetBytes(text2 + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")));
}
string s = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " + text3 + "\r\n\r\n";
sock.Send(Encoding.ASCII.GetBytes(s));
lock (_lock)
{
_clients.Add(sock);
}
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogInfo((object)("panel connected (" + ClientCount + " total)"));
}
Thread thread = new Thread((ThreadStart)delegate
{
ReadLoop(sock);
});
thread.IsBackground = true;
thread.Name = "GlassPanel-read";
thread.Start();
}
else
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("HTTP/1.1 200 OK\r\n");
stringBuilder.Append("Content-Type: text/html; charset=utf-8\r\n");
stringBuilder.Append("Content-Length: ").Append(_pageBytes.Length).Append("\r\n");
stringBuilder.Append("Cache-Control: no-cache\r\nConnection: close\r\n\r\n");
sock.Send(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
sock.Send(_pageBytes);
sock.Close();
}
}
private static string ReadHeaders(NetworkStream stream)
{
byte[] array = new byte[4096];
StringBuilder stringBuilder = new StringBuilder();
stream.ReadTimeout = 5000;
while (stringBuilder.Length < 16384)
{
int num;
try
{
num = stream.Read(array, 0, array.Length);
}
catch
{
return null;
}
if (num <= 0)
{
break;
}
stringBuilder.Append(Encoding.ASCII.GetString(array, 0, num));
if (stringBuilder.ToString().IndexOf("\r\n\r\n", StringComparison.Ordinal) >= 0)
{
break;
}
}
if (stringBuilder.Length != 0)
{
return stringBuilder.ToString();
}
return null;
}
private static string ExtractHeader(string request, string name)
{
string[] array = request.Split(new string[1] { "\r\n" }, StringSplitOptions.None);
foreach (string text in array)
{
int num = text.IndexOf(':');
if (num > 0 && text.Substring(0, num).Trim().Equals(name, StringComparison.OrdinalIgnoreCase))
{
return text.Substring(num + 1).Trim();
}
}
return null;
}
public void Broadcast(string message)
{
byte[] buffer = EncodeTextFrame(message);
lock (_lock)
{
for (int num = _clients.Count - 1; num >= 0; num--)
{
Socket socket = _clients[num];
try
{
socket.Send(buffer);
}
catch
{
try
{
socket.Close();
}
catch
{
}
_clients.RemoveAt(num);
}
}
}
}
private void ReadLoop(Socket sock)
{
try
{
NetworkStream networkStream = new NetworkStream(sock, ownsSocket: false);
while (_running && sock.Connected)
{
int num = networkStream.ReadByte();
if (num < 0)
{
break;
}
int num2 = networkStream.ReadByte();
if (num2 < 0)
{
break;
}
int num3 = num & 0xF;
bool flag = (num2 & 0x80) != 0;
long num4 = num2 & 0x7F;
switch (num4)
{
case 126L:
num4 = (ReadN(networkStream) << 8) | ReadN(networkStream);
break;
case 127L:
{
num4 = 0L;
for (int i = 0; i < 8; i++)
{
num4 = (num4 << 8) | ReadN(networkStream);
}
break;
}
}
if (num4 < 0 || num4 > 65536)
{
break;
}
byte[] array = new byte[4];
if (flag)
{
ReadFull(networkStream, array, 4);
}
byte[] array2 = new byte[num4];
ReadFull(networkStream, array2, (int)num4);
if (flag)
{
for (int j = 0; j < num4; j++)
{
array2[j] ^= array[j & 3];
}
}
switch (num3)
{
case 1:
if (OnMessage != null)
{
OnMessage(Encoding.UTF8.GetString(array2));
}
break;
case 8:
return;
}
}
}
catch
{
}
finally
{
lock (_lock)
{
_clients.Remove(sock);
}
try
{
sock.Close();
}
catch
{
}
}
}
private static int ReadN(NetworkStream ns)
{
int num = ns.ReadByte();
if (num < 0)
{
throw new IOException();
}
return num;
}
private static void ReadFull(NetworkStream ns, byte[] buf, int count)
{
int num;
for (int i = 0; i < count; i += num)
{
num = ns.Read(buf, i, count - i);
if (num <= 0)
{
throw new IOException();
}
}
}
private static byte[] EncodeTextFrame(string message)
{
byte[] bytes = Encoding.UTF8.GetBytes(message);
int num = bytes.Length;
byte[] array = ((num < 126) ? new byte[2]
{
129,
(byte)num
} : ((num > 65535) ? new byte[10]
{
129,
127,
0,
0,
0,
0,
(byte)(num >> 24),
(byte)(num >> 16),
(byte)(num >> 8),
(byte)(num & 0xFF)
} : new byte[4]
{
129,
126,
(byte)(num >> 8),
(byte)(num & 0xFF)
}));
byte[] array2 = new byte[array.Length + num];
Array.Copy(array, array2, array.Length);
Array.Copy(bytes, 0, array2, array.Length, num);
return array2;
}
}
[BepInPlugin("ai.fireballz.noglasspanel", "NO Glass Panel", "1.8.1")]
[BepInProcess("NuclearOption.exe")]
public class Plugin : BaseUnityPlugin
{
public const string GUID = "ai.fireballz.noglasspanel";
internal static ManualLogSource Log;
internal static bool HideWeaponHMD;
private MiniServer _server;
private TelemetryReader _reader;
private float _accum;
private float _interval = 1f / 30f;
private readonly Queue<string> _inbox = new Queue<string>();
private readonly object _inboxLock = new object();
private Aircraft _subAircraft;
private Action<OnRadarWarning> _radarHandler;
private void Awake()
{
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
GameObject managerObject = Chainloader.ManagerObject;
if ((Object)(object)managerObject != (Object)null)
{
((Object)managerObject).hideFlags = (HideFlags)61;
Object.DontDestroyOnLoad((Object)(object)managerObject);
}
int value = ((BaseUnityPlugin)this).Config.Bind<int>("Server", "Port", 8787, "TCP port serving the panel page (HTTP) and the live feed (WebSocket) on the same port.").Value;
float value2 = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "UpdateHz", 30f, "Telemetry frames per second pushed to connected panels.").Value;
_interval = 1f / Mathf.Max(1f, value2);
HideWeaponHMD = ((BaseUnityPlugin)this).Config.Bind<bool>("HMD", "HideWeaponAmmo", false, "Hide the weapon/ammo indicator on the in-game HMD (it lives on the panel instead).").Value;
_reader = new TelemetryReader();
_server = new MiniServer(value, LoadPanelHtml());
_server.OnMessage = OnPanelMessage;
_server.Start();
try
{
new Harmony("ai.fireballz.noglasspanel").PatchAll();
}
catch (Exception ex)
{
Log.LogWarning((object)("chat receive patch skipped: " + ex.Message));
}
Log.LogInfo((object)$"Glass Panel up. On the laptop, open http://<this-pc-ip>:{value}");
}
private void Update()
{
if (_server == null)
{
return;
}
lock (_inboxLock)
{
while (_inbox.Count > 0)
{
HandlePanelMessage(_inbox.Dequeue());
}
}
EnsureRadarSub();
_accum += Time.unscaledDeltaTime;
if (_accum < _interval)
{
return;
}
_accum = 0f;
if (_server.ClientCount != 0)
{
string text = _reader.BuildFrame();
if (text != null)
{
_server.Broadcast(text);
}
}
}
private void OnDestroy()
{
_server?.Stop();
}
private void OnPanelMessage(string msg)
{
lock (_inboxLock)
{
if (_inbox.Count < 32)
{
_inbox.Enqueue(msg);
}
}
}
private void EnsureRadarSub()
{
try
{
Aircraft val = default(Aircraft);
GameManager.GetLocalAircraft(ref val);
if (val == _subAircraft)
{
return;
}
if ((Object)(object)_subAircraft != (Object)null && _radarHandler != null)
{
_subAircraft.onRadarWarning -= _radarHandler;
}
_subAircraft = val;
if (!((Object)(object)val != (Object)null))
{
return;
}
if (_radarHandler == null)
{
_radarHandler = delegate(OnRadarWarning w)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
RadarWarnTracker.Mark(w.radar);
};
}
val.onRadarWarning += _radarHandler;
}
catch
{
}
}
private static void HandlePanelMessage(string json)
{
if (json == null)
{
return;
}
if (json.IndexOf("\"cmd\"", StringComparison.Ordinal) >= 0)
{
HandleCommand(json);
}
else
{
if (json.IndexOf("\"chat\"", StringComparison.Ordinal) < 0)
{
return;
}
bool allChat = json.IndexOf("\"all\":true", StringComparison.Ordinal) >= 0;
int num = json.IndexOf("\"text\":\"", StringComparison.Ordinal);
if (num >= 0)
{
num += 8;
int num2 = json.LastIndexOf('"');
if (num2 > num)
{
ChatBridge.Send(json.Substring(num, num2 - num).Replace("\\\"", "\"").Replace("\\\\", "\\"), allChat);
}
}
}
}
private static void HandleCommand(string json)
{
string text = Extract(json, "\"a\":\"");
Aircraft val = default(Aircraft);
if (text == null || !GameManager.GetLocalAircraft(ref val) || (Object)(object)val == (Object)null)
{
return;
}
try
{
switch (text)
{
case "gear":
val.SetGear(!val.gearDeployed);
break;
case "wpn+":
if ((Object)(object)val.weaponManager != (Object)null)
{
val.weaponManager.NextWeaponStation();
}
break;
case "wpn-":
if ((Object)(object)val.weaponManager != (Object)null)
{
val.weaponManager.PreviousWeaponStation();
}
break;
case "cm":
if (val.countermeasureManager != null)
{
val.countermeasureManager.PopFlares();
}
break;
}
}
catch
{
}
}
private static string Extract(string json, string marker)
{
int num = json.IndexOf(marker, StringComparison.Ordinal);
if (num < 0)
{
return null;
}
num += marker.Length;
int num2 = json.IndexOf('"', num);
if (num2 <= num)
{
return null;
}
return json.Substring(num, num2 - num);
}
private static string LoadPanelHtml()
{
using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GlassPanel.index.html");
if (stream == null)
{
return "<!doctype html><h1>panel resource missing from mod build</h1>";
}
using StreamReader streamReader = new StreamReader(stream);
return streamReader.ReadToEnd();
}
}
internal static class RadarWarnTracker
{
private static readonly Dictionary<Radar, float> _hits = new Dictionary<Radar, float>();
private static readonly object _lock = new object();
private const float TTL = 4f;
public static void Mark(Radar r)
{
if ((Object)(object)r == (Object)null)
{
return;
}
lock (_lock)
{
_hits[r] = Time.time;
}
}
public static List<Radar> Active()
{
List<Radar> list = new List<Radar>();
lock (_lock)
{
float time = Time.time;
List<Radar> list2 = null;
foreach (KeyValuePair<Radar, float> hit in _hits)
{
if ((Object)(object)hit.Key == (Object)null || time - hit.Value > 4f)
{
(list2 ?? (list2 = new List<Radar>())).Add(hit.Key);
}
else
{
list.Add(hit.Key);
}
}
if (list2 != null)
{
foreach (Radar item in list2)
{
_hits.Remove(item);
}
}
}
return list;
}
}
internal class TelemetryReader
{
private const float MS_TO_KN = 1.943844f;
private const float M_TO_FT = 3.28084f;
private const float MS_TO_FTMIN = 196.8504f;
private const float RAD_TO_DEG = 57.29578f;
public string BuildFrame()
{
//IL_003c: 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)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0199: Unknown result type (might be due to invalid IL or missing references)
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
Aircraft val = default(Aircraft);
if (!GameManager.GetLocalAircraft(ref val) || (Object)(object)val == (Object)null)
{
return null;
}
Transform transform = ((Component)val).transform;
Vector3 val2 = (((Object)(object)val.cockpit != (Object)null && (Object)(object)val.cockpit.rb != (Object)null) ? val.cockpit.rb.velocity : Vector3.zero);
float speed = ((Unit)val).speed;
float x = transform.eulerAngles.x;
float z = transform.eulerAngles.z;
float v = ((x > 180f) ? (360f - x) : (0f - x));
float v2 = ((z > 180f) ? (360f - z) : (0f - z));
float y = transform.eulerAngles.y;
float v3 = 0f;
if ((Object)(object)val.cockpit != (Object)null)
{
Vector3 val3 = ((Component)val.cockpit).transform.InverseTransformDirection(val2);
v3 = Mathf.Atan2(val3.y, val3.z) * -57.29578f;
}
ControlInputs inputs = val.GetInputs();
float num = GlobalPositionExtensions.GlobalY(transform.position);
float num2 = Mathf.Pow(Mathf.Max(0.05f, 1f - 2.25577E-05f * Mathf.Max(0f, num)), 4.2561f);
List<string> list = new List<string>(28);
list.Add(Num("tas", speed * 1.943844f));
list.Add(Num("ias", speed * Mathf.Sqrt(num2) * 1.943844f));
list.Add(Num("mach", speed / 340f));
list.Add(Num("alt", GlobalPositionExtensions.GlobalY(transform.position) * 3.28084f));
list.Add(Num("agl", Mathf.Max(0f, ((Unit)val).radarAlt) * 3.28084f));
list.Add(Num("vs", val2.y * 196.8504f));
list.Add(Num("hdg", y));
list.Add(Num("pitch", v));
list.Add(Num("roll", v2));
list.Add(Num("aoa", v3));
list.Add(Num("g", val.gForce));
list.Add(Num("engine", EngineThrustKN(val)));
list.Add(Num("throttle", inputs.throttle));
list.Add(Bool("gear", val.gearDeployed));
list.Add(Num("fuelKg", val.GetFuelQuantity()));
list.Add("\"inputs\":{" + Num("pitch", inputs.pitch) + "," + Num("roll", inputs.roll) + "," + Num("yaw", inputs.yaw) + "," + Num("throttle", inputs.throttle) + "}");
list.Add("\"weapons\":[" + BuildLoadout(val, out var selIndex) + "]");
list.Add(Int("weaponIndex", selIndex));
int flares = 0;
int chaff = 0;
int flaresMax = 0;
int chaffMax = 0;
ReadCountermeasures(val, ref flares, ref chaff, ref flaresMax, ref chaffMax);
list.Add(Int("flares", flares));
list.Add(Int("chaff", chaff));
list.Add(Int("flaresMax", (flaresMax <= 0) ? 1 : flaresMax));
list.Add(Int("chaffMax", (chaffMax <= 0) ? 1 : chaffMax));
list.Add("\"contacts\":[" + BuildContacts(val) + "]");
list.Add("\"rwr\":[" + BuildRWR(val) + "]");
list.Add(BuildDamage(val));
list.Add("\"chat\":[" + ChatBridge.BuildJson() + "]");
list.Add("\"datalink\":[" + BuildDatalink(val) + "]");
list.Add(BuildNav(val));
list.Add("\"objectives\":[" + BuildObjectives() + "]");
return "{" + string.Join(",", list.ToArray()) + "}";
}
private static float EngineThrustKN(Aircraft ac)
{
try
{
float num = 0f;
if (ac.engines != null)
{
foreach (IEngine engine in ac.engines)
{
if (engine != null)
{
num += engine.GetThrust();
}
}
}
return num / 1000f;
}
catch
{
return 0f;
}
}
private static string BuildLoadout(Aircraft ac, out int selIndex)
{
selIndex = 0;
try
{
List<WeaponStation> weaponStations = ((Unit)ac).weaponStations;
if (weaponStations == null)
{
return BuildSelectedWeapon(ac);
}
WeaponStation val = (((Object)(object)ac.weaponManager != (Object)null) ? ac.weaponManager.currentWeaponStation : null);
List<string> list = new List<string>();
foreach (WeaponStation item in weaponStations)
{
if (item != null && !((Object)(object)item.WeaponInfo == (Object)null))
{
string text = ((!string.IsNullOrEmpty(item.WeaponInfo.weaponName)) ? item.WeaponInfo.weaponName : item.WeaponInfo.shortName);
if (val != null && item == val)
{
selIndex = list.Count;
}
list.Add("{" + Str("name", text ?? "-") + "," + Int("ammo", item.Ammo) + "," + Str("unit", "") + "}");
}
}
return (list.Count > 0) ? string.Join(",", list.ToArray()) : BuildSelectedWeapon(ac);
}
catch
{
selIndex = 0;
return BuildSelectedWeapon(ac);
}
}
private static string BuildSelectedWeapon(Aircraft ac)
{
WeaponManager weaponManager = ac.weaponManager;
WeaponStation val = (((Object)(object)weaponManager != (Object)null) ? weaponManager.currentWeaponStation : null);
if (val == null || (Object)(object)val.WeaponInfo == (Object)null)
{
return "";
}
string text = ((!string.IsNullOrEmpty(val.WeaponInfo.weaponName)) ? val.WeaponInfo.weaponName : val.WeaponInfo.shortName);
return "{" + Str("name", text ?? "-") + "," + Int("ammo", val.Ammo) + "," + Str("unit", "RDS") + "}";
}
private static void ReadCountermeasures(Aircraft ac, ref int flares, ref int chaff, ref int flaresMax, ref int chaffMax)
{
try
{
CountermeasureManager countermeasureManager = ac.countermeasureManager;
if (countermeasureManager == null || !(typeof(CountermeasureManager).GetField("countermeasureStations", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(countermeasureManager) is IEnumerable enumerable))
{
return;
}
foreach (object item in enumerable)
{
if (item != null)
{
Type type = item.GetType();
int num = (int)(type.GetField("ammo")?.GetValue(item) ?? ((object)0));
int num2 = (int)(type.GetField("maxAmmo")?.GetValue(item) ?? ((object)0));
if (type.GetField("threatTypes")?.GetValue(item) is List<string> list && list.Exists((string x) => x?.ToLower().Contains("radar") ?? false))
{
chaff += num;
chaffMax += num2;
}
else
{
flares += num;
flaresMax += num2;
}
}
}
}
catch
{
}
}
private static string BuildContacts(Aircraft ac)
{
//IL_0067: 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_0077: 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_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
try
{
WeaponManager weaponManager = ac.weaponManager;
List<Unit> list = (((Object)(object)weaponManager != (Object)null) ? weaponManager.GetTargetList() : null);
if (list == null)
{
return "";
}
List<string> list2 = new List<string>();
int num = 0;
foreach (Unit item in list)
{
if (!((Object)(object)item == (Object)null) && num < 12)
{
num++;
Vector3 val = ((Component)item).transform.position - ((Component)ac).transform.position;
float magnitude = ((Vector3)(ref val)).magnitude;
float v = (Mathf.Atan2(val.x, val.z) * 57.29578f + 360f) % 360f;
list2.Add("{" + Num("brg", v) + "," + Num("rng", magnitude) + "," + Str("type", "H") + "}");
}
}
return string.Join(",", list2.ToArray());
}
catch
{
return "";
}
}
private static string BuildRWR(Aircraft ac)
{
//IL_0137: 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_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: 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_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: 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)
try
{
List<string> list = new List<string>();
MissileWarning missileWarningSystem = ac.GetMissileWarningSystem();
if ((Object)(object)missileWarningSystem != (Object)null && missileWarningSystem.knownMissiles != null)
{
foreach (Missile knownMissile in missileWarningSystem.knownMissiles)
{
if (!((Object)(object)knownMissile == (Object)null))
{
Vector3 val = ((Component)knownMissile).transform.position - ((Component)ac).transform.position;
float v = (Mathf.Atan2(val.x, val.z) * 57.29578f + 360f) % 360f;
list.Add("{" + Num("brg", v) + "," + Str("band", "M") + "," + Int("lock", 2) + "}");
}
}
}
foreach (Radar item in RadarWarnTracker.Active())
{
if (!((Object)(object)item == (Object)null))
{
Vector3 val2 = ((Component)item).transform.position - ((Component)ac).transform.position;
float v2 = (Mathf.Atan2(val2.x, val2.z) * 57.29578f + 360f) % 360f;
list.Add("{" + Num("brg", v2) + "," + Str("band", "R") + "," + Int("lock", 1) + "}");
}
}
return string.Join(",", list.ToArray());
}
catch
{
return "";
}
}
private static string BuildDatalink(Aircraft ac)
{
//IL_0090: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
try
{
FactionHQ networkHQ = ((Unit)ac).NetworkHQ;
if ((Object)(object)networkHQ == (Object)null || networkHQ.trackingDatabase == null)
{
return "";
}
Faction faction = networkHQ.faction;
List<string> list = new List<string>();
int num = 0;
Unit val = default(Unit);
foreach (KeyValuePair<PersistentID, TrackingInfo> item in networkHQ.trackingDatabase)
{
if (num < 40)
{
TrackingInfo value = item.Value;
if (value != null && value.TryGetUnit(ref val) && !((Object)(object)val == (Object)null) && (object)val != ac)
{
Vector3 val2 = ((Component)val).transform.position - ((Component)ac).transform.position;
float magnitude = ((Vector3)(ref val2)).magnitude;
float v = (Mathf.Atan2(val2.x, val2.z) * 57.29578f + 360f) % 360f;
Faction val3 = (((Object)(object)val.NetworkHQ != (Object)null) ? val.NetworkHQ.faction : null);
string v2 = (((Object)(object)faction != (Object)null && (Object)(object)val3 != (Object)null && (Object)(object)faction == (Object)(object)val3) ? "F" : "H");
list.Add("{" + Num("brg", v) + "," + Num("rng", magnitude) + "," + Str("type", v2) + "}");
num++;
}
continue;
}
break;
}
return string.Join(",", list.ToArray());
}
catch
{
return "";
}
}
private static string BuildDamage(Aircraft ac)
{
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
float v = 1f;
float v2 = 1f;
float v3 = 1f;
float v4 = 1f;
float v5 = 1f;
float v6 = 1f;
string v7 = "";
string v8 = "";
try
{
if (ac.partDamageTracker != null)
{
v = 1f - ac.partDamageTracker.GetDetachedRatio();
}
if ((Object)(object)ac.definition != (Object)null)
{
v7 = ((UnitDefinition)ac.definition).unitName ?? "";
v8 = ((UnitDefinition)ac.definition).code ?? "";
}
foreach (UnitPart allPart in ((Unit)ac).GetAllParts())
{
if (!((Object)(object)allPart == (Object)null) && allPart.IsDetached())
{
Vector3 localPosition = ((Component)allPart).transform.localPosition;
if (localPosition.x < -0.8f)
{
v3 = 0f;
}
else if (localPosition.x > 0.8f)
{
v4 = 0f;
}
else if (localPosition.z > 1f)
{
v2 = 0f;
}
else if (localPosition.z < -1f)
{
v5 = 0f;
}
else
{
v6 = 0.3f;
}
}
}
}
catch
{
}
return "\"damage\":{" + Num("hull", v) + "," + Str("name", v7) + "," + Str("code", v8) + ",\"sections\":{" + Num("nose", v2) + "," + Num("lwing", v3) + "," + Num("rwing", v4) + "," + Num("tail", v5) + "," + Num("engine", v6) + "}}";
}
private static string BuildNav(Aircraft ac)
{
//IL_001a: 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_0029: 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_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: 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_007c: Unknown result type (might be due to invalid IL or missing references)
try
{
FactionHQ networkHQ = ((Unit)ac).NetworkHQ;
Airbase val = default(Airbase);
if ((Object)(object)networkHQ != (Object)null && networkHQ.TryGetNearestAirbase(((Component)ac).transform.position, ref val, default(RunwayQuery)) && (Object)(object)val != (Object)null && (Object)(object)val.center != (Object)null)
{
Vector3 val2 = val.center.position - ((Component)ac).transform.position;
float magnitude = ((Vector3)(ref val2)).magnitude;
float v = (Mathf.Atan2(val2.x, val2.z) * 57.29578f + 360f) % 360f;
string networknetworkUniqueName = val.NetworknetworkUniqueName;
return "\"nav\":{" + Str("name", string.IsNullOrEmpty(networknetworkUniqueName) ? "BASE" : networknetworkUniqueName) + "," + Num("brg", v) + "," + Num("rng", magnitude) + "}";
}
}
catch
{
}
return "\"nav\":null";
}
private static string BuildObjectives()
{
try
{
MissionObjectives objectives = MissionManager.Objectives;
if (objectives == null || objectives.AllObjectives == null)
{
return "";
}
List<string> list = new List<string>();
foreach (Objective allObjective in objectives.AllObjectives)
{
if (allObjective == null)
{
continue;
}
string text = null;
try
{
text = allObjective.ToUIString(false);
}
catch
{
}
if (string.IsNullOrEmpty(text))
{
try
{
text = ((object)allObjective).ToString();
}
catch
{
}
}
string v = "";
try
{
v = ((object)Unsafe.As<ObjectiveStatus, ObjectiveStatus>(ref allObjective.Status)/*cast due to .constrained prefix*/).ToString();
}
catch
{
}
float v2 = 0f;
try
{
v2 = allObjective.CompletePercent;
}
catch
{
}
list.Add("{" + Str("text", text ?? "") + "," + Str("status", v) + "," + Num("pct", v2) + "}");
}
return string.Join(",", list.ToArray());
}
catch
{
return "";
}
}
private static string Num(string k, float v)
{
if (float.IsNaN(v) || float.IsInfinity(v))
{
v = 0f;
}
return "\"" + k + "\":" + v.ToString("0.###", CultureInfo.InvariantCulture);
}
private static string Int(string k, int v)
{
return "\"" + k + "\":" + v.ToString(CultureInfo.InvariantCulture);
}
private static string Bool(string k, bool v)
{
return "\"" + k + "\":" + (v ? "true" : "false");
}
private static string Str(string k, string v)
{
return "\"" + k + "\":\"" + Esc(v) + "\"";
}
private static string Esc(string s)
{
if (s != null)
{
return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
}
return "";
}
}