Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LCBridgeOverlay v1.7.0
LCBridgeOverlay.dll
Decompiled a week 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.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DunGen.Graph; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; 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("LCBridgeOverlay")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.7.0.0")] [assembly: AssemblyInformationalVersion("1.7.0+17fc156b395de3c6ab1418d8755000fb34456ed4")] [assembly: AssemblyProduct("LCBridgeOverlay")] [assembly: AssemblyTitle("LCBridgeOverlay")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.7.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LCBridgeOverlay { public static class BcmeClientEvents { private class Entry { public string Header; public string Body; public bool Warn; } private static readonly List<Entry> _entries = new List<Entry>(); private static readonly object _lock = new object(); private static bool _knownSearched; private static FieldInfo[] _eventListFields; private static readonly Dictionary<Type, MethodInfo> _nameMethods = new Dictionary<Type, MethodInfo>(); private static HashSet<string> _knownNames; private static float _knownRefreshed; private static bool _panelSearched; private static PropertyInfo _netInstance; private static PropertyInfo _netVarValue; private static PropertyInfo _uiInstance; private static FieldInfo _textUiField; private static FieldInfo _panelTextField; private static string _lastRaw; public static bool Any => Get().Count > 0; public static void OnDisplayTip(string headerText, string bodyText, bool isWarning) { try { string text = (headerText ?? "").Trim(); string text2 = (bodyText ?? "").Trim(); if (text.Length == 0 && text2.Length == 0) { return; } lock (_lock) { foreach (Entry entry in _entries) { if (entry.Header == text && entry.Body == text2) { return; } } _entries.Add(new Entry { Header = text, Body = text2, Warn = isWarning }); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[bcme-client] анонс ивента: header=\"{text}\" body=\"{text2}\" warn={isWarning}"); } BridgeTicker.ForceImmediate(); } catch { } } public static void Clear() { lock (_lock) { if (_entries.Count > 0) { _entries.Clear(); } } _lastRaw = null; } public static List<BcmerEvents.EventInfo> Get() { List<BcmerEvents.EventInfo> list = new List<BcmerEvents.EventInfo>(); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string item in NamesFromPanel()) { if (hashSet.Add(item)) { list.Add(new BcmerEvents.EventInfo { Name = (ConfigSettings.RussianActive ? EventTranslate.ToRu(item) : item), ColorHex = "#FFFFFF" }); } } lock (_lock) { foreach (Entry entry in _entries) { string text = ((!string.IsNullOrEmpty(entry.Header)) ? entry.Header : entry.Body); if (!string.IsNullOrEmpty(text) && hashSet.Add(text)) { list.Add(new BcmerEvents.EventInfo { Name = text, ColorHex = (entry.Warn ? "#FF5141" : "#FFFFFF") }); } } return list; } } private static HashSet<string> KnownEventNames() { if (_knownNames != null && _knownNames.Count > 0 && Time.unscaledTime - _knownRefreshed < 30f) { return _knownNames; } HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); try { if (!_knownSearched) { _knownSearched = true; Type type = GameState.FindTypeByFullName("BrutalCompanyMinus.Minus.EventManager") ?? GameState.FindTypeFuzzy("BrutalCompany", new string[1] { "EventManager" }); if (type != null) { string[] obj = new string[4] { "events", "vanillaEvents", "moddedEvents", "customEvents" }; List<FieldInfo> list = new List<FieldInfo>(); string[] array = obj; foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { list.Add(field); } } _eventListFields = list.ToArray(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[bcme-client] списков ивентов найдено: {list.Count}"); } } } if (_eventListFields == null) { return _knownNames ?? hashSet; } FieldInfo[] eventListFields = _eventListFields; for (int i = 0; i < eventListFields.Length; i++) { if (!(eventListFields[i].GetValue(null) is IEnumerable enumerable)) { continue; } foreach (object item in enumerable) { if (item != null) { string text = EventName(item); if (!string.IsNullOrEmpty(text)) { hashSet.Add(text.Trim()); } } } } } catch { } if (hashSet.Count > 0) { if (_knownNames == null || _knownNames.Count != hashSet.Count) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[bcme-client] известных имён ивентов: {hashSet.Count}"); } } _knownNames = hashSet; _knownRefreshed = Time.unscaledTime; } return _knownNames ?? hashSet; } private static string EventName(object ev) { try { Type type = ev.GetType(); if (!_nameMethods.TryGetValue(type, out var value)) { value = type.GetMethod("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); _nameMethods[type] = value; } return (value != null) ? (value.Invoke(ev, null) as string) : null; } catch { return null; } } private static string PanelRaw() { try { if (!_panelSearched) { _panelSearched = true; Type type = GameState.FindTypeByFullName("BrutalCompanyMinus.Net") ?? GameState.FindTypeFuzzy("BrutalCompany", new string[1] { "Net" }); if (type != null) { _netInstance = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _textUiField = type.GetField("textUI", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } Type type2 = GameState.FindTypeByFullName("BrutalCompanyMinus.UI") ?? GameState.FindTypeFuzzy("BrutalCompany", new string[1] { "UI" }); if (type2 != null) { _uiInstance = type2.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _panelTextField = type2.GetField("panelText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[bcme-client] Net.textUI=" + ((_textUiField != null) ? "OK" : "нет") + ", UI.panelText=" + ((_panelTextField != null) ? "OK" : "нет"))); } } if (_netInstance != null && _textUiField != null) { object value = _netInstance.GetValue(null); if (value != null) { object value2 = _textUiField.GetValue(value); if (value2 != null) { if (_netVarValue == null) { _netVarValue = value2.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); } string text = ((_netVarValue != null) ? _netVarValue.GetValue(value2) : null)?.ToString(); if (!string.IsNullOrEmpty(text)) { return text; } } } } if (_uiInstance != null && _panelTextField != null) { object value3 = _uiInstance.GetValue(null); if (value3 != null) { object value4 = _panelTextField.GetValue(value3); if (value4 != null) { PropertyInfo property = value4.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public); string text2 = ((property != null) ? property.GetValue(value4) : null)?.ToString(); if (!string.IsNullOrEmpty(text2)) { return text2; } } } } } catch { } return null; } private static List<string> NamesFromPanel() { List<string> list = new List<string>(); try { string text = PanelRaw(); if (string.IsNullOrEmpty(text)) { return list; } if (text != _lastRaw) { _lastRaw = text; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[bcme-client] панель BCME: " + Regex.Replace(text, "<.*?>", "").Replace("\n", " | "))); } } HashSet<string> hashSet = KnownEventNames(); if (hashSet == null || hashSet.Count == 0) { return list; } string[] array = text.Split('\n'); for (int i = 0; i < array.Length; i++) { string text2 = Regex.Replace(array[i] ?? "", "<.*?>", "").Trim(); if (text2.Length == 0) { continue; } if (hashSet.Contains(text2)) { if (!list.Contains(text2)) { list.Add(text2); } } else { if (text2.IndexOf(',') < 0) { continue; } string[] array2 = text2.Split(','); for (int j = 0; j < array2.Length; j++) { string text3 = array2[j].Trim(); if (text3.Length > 0 && hashSet.Contains(text3) && !list.Contains(text3)) { list.Add(text3); } } } } } catch { } return list; } } public static class BcmerEvents { public struct EventInfo { public string Name; public string ColorHex; } private static Type _emType; private static FieldInfo _curEventsField; private static bool _searched; private static readonly Dictionary<Type, MethodInfo> _nameCache = new Dictionary<Type, MethodInfo>(); private static readonly Dictionary<Type, Func<object, string>> _typeGetterCache = new Dictionary<Type, Func<object, string>>(); private static string ColorFor(string typeName) { string text = (typeName ?? "").ToLowerInvariant(); if (text.Contains("verygood") || text.Contains("great")) { return "#00FF00"; } if (text.Contains("good")) { return "#008000"; } if (text.Contains("verybad")) { return "#8B0000"; } if (text.Contains("bad")) { return "#FF0000"; } if (text.Contains("black") || text.Contains("deadly") || text.Contains("impossible") || text.Contains("death")) { return "#000000"; } return "#FFFFFF"; } public static List<EventInfo> GetEvents() { List<EventInfo> list = new List<EventInfo>(); try { EnsureSearched(); if (_curEventsField == null) { return list; } if (!(_curEventsField.GetValue(null) is IEnumerable enumerable)) { return list; } foreach (object item in enumerable) { if (item == null) { continue; } string text = GetName(item); if (!string.IsNullOrEmpty(text)) { if (ConfigSettings.RussianActive) { text = EventTranslate.ToRu(text); } list.Add(new EventInfo { Name = text, ColorHex = ColorFor(GetEventTypeName(item)) }); } } } catch { } if (list.Count == 0 && BcmeClientEvents.Any) { list.AddRange(BcmeClientEvents.Get()); } return list; } public static bool BcmePresent() { try { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { if (pluginInfo.Key.IndexOf("BrutalCompany", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } PluginInfo value = pluginInfo.Value; object obj; if (value == null) { obj = null; } else { BepInPlugin metadata = value.Metadata; obj = ((metadata != null) ? metadata.Name : null); } if (obj == null) { obj = ""; } if (((string)obj).IndexOf("BrutalCompany", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } catch { } return false; } private static void EnsureSearched() { if (_searched) { return; } _searched = true; if (!BcmePresent()) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"BCME не найден в Chainloader.PluginInfos — плашка ивентов возьмёт данные моста."); } return; } _emType = FindTypeByFullName("BrutalCompanyMinus.Minus.EventManager") ?? FindTypeFuzzy("BrutalCompany", "EventManager"); if (_emType != null) { _curEventsField = _emType.GetField("currentEvents", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[reflection] BCMER EventManager=" + _emType.FullName + ", currentEvents=" + ((_curEventsField != null) ? "OK" : "НЕ НАЙДЕНО"))); } } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)"[reflection] BCMER не найден (не установлен?) — плашка ивентов возьмёт данные моста."); } } } private static string GetName(object ev) { Type type = ev.GetType(); if (!_nameCache.TryGetValue(type, out var value)) { value = type.GetMethod("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); _nameCache[type] = value; } if (value != null) { try { return value.Invoke(ev, null) as string; } catch { } } return ev.ToString(); } private static string GetEventTypeName(object ev) { Type type = ev.GetType(); if (!_typeGetterCache.TryGetValue(type, out var value)) { value = BuildTypeGetter(type); _typeGetterCache[type] = value; } try { return value?.Invoke(ev); } catch { return null; } } private static Func<object, string> BuildTypeGetter(Type t) { string[] array = new string[6] { "Type", "EventType", "type", "eventType", "Rarity", "rarity" }; string[] array2 = array; foreach (string name in array2) { MethodInfo m = t.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (m != null && (m.ReturnType.IsEnum || m.ReturnType == typeof(string))) { return (object o) => m.Invoke(o, null)?.ToString(); } } array2 = array; foreach (string name2 in array2) { PropertyInfo p = t.GetProperty(name2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (p != null && p.CanRead && (p.PropertyType.IsEnum || p.PropertyType == typeof(string))) { return (object o) => p.GetValue(o)?.ToString(); } } array2 = array; foreach (string name3 in array2) { FieldInfo f = t.GetField(name3, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (f != null && (f.FieldType.IsEnum || f.FieldType == typeof(string))) { return (object o) => f.GetValue(o)?.ToString(); } } return null; } private static Type FindTypeByFullName(string fullName) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type type = null; try { type = assembly.GetType(fullName, throwOnError: false); } catch { } if (type != null) { return type; } } } catch { } return null; } private static Type FindTypeFuzzy(string asmNameContains, string typeName) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if ((assembly.GetName().Name ?? "").IndexOf(asmNameContains, StringComparison.OrdinalIgnoreCase) < 0) { continue; } Type[] source; try { source = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { source = ex.Types.Where((Type x) => x != null).ToArray(); } Type type = source.FirstOrDefault((Type x) => string.Equals(x.Name, typeName, StringComparison.OrdinalIgnoreCase)); if (type != null) { return type; } } } catch { } return null; } } public static class BridgeServer { private static TcpListener _listener; private static Thread _acceptThread; private static volatile bool _running; private static readonly List<TcpClient> _clients = new List<TcpClient>(); private static readonly object _lock = new object(); private static volatile string _lastPayload; public static bool IsRunning => _running; public static void Start(int port) { if (!_running) { _running = true; _listener = new TcpListener(IPAddress.Loopback, port); _listener.Start(); _acceptThread = new Thread(AcceptLoop) { IsBackground = true, Name = "LCBridge-Accept" }; _acceptThread.Start(); } } public static void Stop() { _running = false; try { _listener?.Stop(); } catch { } lock (_lock) { foreach (TcpClient client in _clients) { try { client.Close(); } catch { } } _clients.Clear(); } } private static void AcceptLoop() { while (_running) { try { TcpClient tcpClient = _listener.AcceptTcpClient(); if (Handshake(tcpClient)) { string lastPayload = _lastPayload; if (lastPayload != null) { try { byte[] array = EncodeTextFrame(lastPayload); tcpClient.GetStream().Write(array, 0, array.Length); } catch { } } lock (_lock) { _clients.Add(tcpClient); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"Оверлей подключился к мосту."); } } else { try { tcpClient.Close(); } catch { } } } catch { if (!_running) { break; } } } } private static bool Handshake(TcpClient client) { try { NetworkStream stream = client.GetStream(); byte[] array = new byte[4096]; int num = stream.Read(array, 0, array.Length); if (num <= 0) { return false; } string text = Encoding.UTF8.GetString(array, 0, num); string text2 = null; string[] array2 = text.Split(new string[1] { "\r\n" }, StringSplitOptions.None); foreach (string text3 in array2) { if (text3.StartsWith("Sec-WebSocket-Key:", StringComparison.OrdinalIgnoreCase)) { text2 = text3.Substring("Sec-WebSocket-Key:".Length).Trim(); break; } } if (text2 == null) { return false; } string text4; using (SHA1 sHA = SHA1.Create()) { text4 = 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: " + text4 + "\r\n\r\n"; byte[] bytes = Encoding.UTF8.GetBytes(s); stream.Write(bytes, 0, bytes.Length); return true; } catch { return false; } } public static void Broadcast(string text) { _lastPayload = text; byte[] array = EncodeTextFrame(text); List<TcpClient> list = null; lock (_lock) { foreach (TcpClient client in _clients) { try { if (!client.Connected) { (list ?? (list = new List<TcpClient>())).Add(client); } else { client.GetStream().Write(array, 0, array.Length); } } catch { (list ?? (list = new List<TcpClient>())).Add(client); } } if (list == null) { return; } foreach (TcpClient item in list) { _clients.Remove(item); try { item.Close(); } catch { } } } } private static byte[] EncodeTextFrame(string text) { byte[] bytes = Encoding.UTF8.GetBytes(text); int num = bytes.Length; byte[] array; if (num <= 125) { array = new byte[2] { 0, (byte)num }; } else if (num <= 65535) { array = new byte[4] { 0, 126, (byte)((num >> 8) & 0xFF), (byte)(num & 0xFF) }; } else { array = new byte[10] { 0, 127, 0, 0, 0, 0, 0, 0, 0, 0 }; for (int i = 0; i < 8; i++) { array[9 - i] = (byte)((num >> 8 * i) & 0xFF); } } array[0] = 129; byte[] array2 = new byte[array.Length + bytes.Length]; Buffer.BlockCopy(array, 0, array2, 0, array.Length); Buffer.BlockCopy(bytes, 0, array2, array.Length, bytes.Length); return array2; } } public class BridgeTicker : MonoBehaviour { private float _timer; private const float Interval = 1f; private string _lastPayload; private int _lastMobCount = -1; private static volatile bool _forceNow; public static void ForceImmediate() { _forceNow = true; } private void Update() { _timer += Time.deltaTime; if (_forceNow) { _forceNow = false; _timer = 1f; } if (_timer < 1f) { return; } _timer = 0f; DataParser.Heartbeat = Time.unscaledTime; GameState.TickStats(); RunStats.Tick(); OverlayNet.Tick(); MonsterState.Tick(GameState.GetAllLiveEnemies()); string text = BuildJson(); if (text != _lastPayload) { _lastPayload = text; if (BridgeServer.IsRunning) { BridgeServer.Broadcast(text); } DataParser.PushLocal(text); } } private string BuildJson() { (int alive, int total) crew = GameState.GetCrew(); int item = crew.alive; int item2 = crew.total; int value = (OverlayNet.HasHostState ? OverlayNet.HostDeaths : GameState.GetDeaths()); int localHealth = GameState.GetLocalHealth(); string moonName = GameState.GetMoonName(); string weatherTweaksWeather = GameState.GetWeatherTweaksWeather(); string s = ((!string.IsNullOrEmpty(weatherTweaksWeather)) ? weatherTweaksWeather : GameState.GetVanillaWeather()); string text = (Gate.Events ? GameState.GetBrutalEvent() : null); List<string> list; List<string> list2; if (Gate.Monsters) { (list, list2) = GameState.GetMonsters(); } else { List<string> list3 = new List<string>(); List<string> list4 = new List<string>(); list2 = list4; list = list3; } List<string> items = (Gate.Traps ? GameState.GetTraps() : new List<string>()); bool onMoon = GameState.GetOnMoon(); bool loading = GameState.GetLoading(); bool inGame = GameState.GetInGame(); int value2 = (OverlayNet.HasHostState ? OverlayNet.HostResetToken : GameState.GetResetToken()); int value3 = (Gate.LevelScrap ? GameState.GetLevelScrap() : 0); (int quota, int fulfilled) quotaProgress = GameState.GetQuotaProgress(); int item3 = quotaProgress.quota; int item4 = quotaProgress.fulfilled; int shipScrapSafe = GameState.GetShipScrapSafe(); int quotaIndexSafe = GameState.GetQuotaIndexSafe(); int dayCount = GameState.GetDayCount(); int daysLeft = GameState.GetDaysLeft(); string text2 = (Gate.Interior ? GameState.GetInterior() : null); int value4; int value5; int value6; if (Gate.LevelLoot) { (value4, value5, value6) = GameState.GetLootBreakdown(); } else { value4 = 0; value5 = 0; value6 = 0; } bool oldBird = GameState.GetOldBird(); bool onShip = GameState.GetOnShip(); string topKiller = GameState.GetTopKiller(); string topMonster = GameState.GetTopMonster(); string deadliestEvent = GameState.GetDeadliestEvent(); bool flag = GameExtras.PopupActive(); bool flag2 = GameExtras.StoreAdActive(); int value7 = (Gate.Countdown ? GameExtras.SecondsToEndOfDay() : (-1)); bool flag3 = Gate.Apparatus && GameExtras.ApparatusInside(); float num = (Gate.LootMult ? GameExtras.LootMultiplier() : 1f); int soldTotal = RunStats.SoldTotal; int num2 = list.Count + list2.Count; if (num2 != _lastMobCount) { _lastMobCount = num2; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)string.Format("[monsters] улица={0} ({1}) | комплекс={2} ({3})", list.Count, string.Join(",", list), list2.Count, string.Join(",", list2))); } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append('{'); stringBuilder.Append("\"type\":\"bridge\","); stringBuilder.Append("\"deaths\":").Append(value).Append(','); stringBuilder.Append("\"alive\":").Append(item).Append(','); stringBuilder.Append("\"total\":").Append(item2).Append(','); stringBuilder.Append("\"health\":").Append(localHealth).Append(','); stringBuilder.Append("\"moonName\":").Append(JsonStr(moonName)).Append(','); stringBuilder.Append("\"weatherFull\":").Append(JsonStr(s)).Append(','); stringBuilder.Append("\"brutalEvent\":").Append(JsonStr(text ?? "")).Append(','); stringBuilder.Append("\"onMoon\":").Append(onMoon ? "true" : "false").Append(','); stringBuilder.Append("\"loading\":").Append(loading ? "true" : "false").Append(','); stringBuilder.Append("\"inGame\":").Append(inGame ? "true" : "false").Append(','); stringBuilder.Append("\"resetToken\":").Append(value2).Append(','); stringBuilder.Append("\"levelScrap\":").Append(value3).Append(','); stringBuilder.Append("\"quotaValue\":").Append(item3).Append(','); stringBuilder.Append("\"quotaFulfilled\":").Append(item4).Append(','); stringBuilder.Append("\"shipLoot\":").Append(shipScrapSafe).Append(','); stringBuilder.Append("\"quotaIndex\":").Append(quotaIndexSafe).Append(','); stringBuilder.Append("\"dayCount\":").Append(dayCount).Append(','); stringBuilder.Append("\"daysLeft\":").Append(daysLeft).Append(','); stringBuilder.Append("\"interiorType\":").Append(JsonStr(text2 ?? "")).Append(','); stringBuilder.Append("\"beehiveCount\":").Append(value4).Append(','); stringBuilder.Append("\"itemsInside\":").Append(value5).Append(','); stringBuilder.Append("\"itemsOutside\":").Append(value6).Append(','); stringBuilder.Append("\"hasOldBird\":").Append(oldBird ? "true" : "false").Append(','); stringBuilder.Append("\"onShip\":").Append(onShip ? "true" : "false").Append(','); stringBuilder.Append("\"popupActive\":").Append(flag ? "true" : "false").Append(','); stringBuilder.Append("\"storeAdActive\":").Append(flag2 ? "true" : "false").Append(','); stringBuilder.Append("\"endOfDaySec\":").Append(value7).Append(','); stringBuilder.Append("\"apparatusInside\":").Append(flag3 ? "true" : "false").Append(','); stringBuilder.Append("\"lootMultiplier\":").Append(num.ToString("0.##", CultureInfo.InvariantCulture)).Append(','); stringBuilder.Append("\"soldLoot\":").Append(soldTotal).Append(','); stringBuilder.Append("\"topKiller\":").Append(JsonStr(topKiller ?? "")).Append(','); stringBuilder.Append("\"topMonster\":").Append(JsonStr(topMonster ?? "")).Append(','); stringBuilder.Append("\"deadliestEvent\":").Append(JsonStr(deadliestEvent ?? "")).Append(','); stringBuilder.Append("\"monstersOutside\":").Append(JsonArr(list)).Append(','); stringBuilder.Append("\"monstersInside\":").Append(JsonArr(list2)).Append(','); stringBuilder.Append("\"traps\":").Append(JsonArr(items)).Append(','); stringBuilder.Append("\"run\":").Append(RunStats.ToJson()); stringBuilder.Append('}'); return stringBuilder.ToString(); } private static string JsonArr(List<string> items) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append('['); for (int i = 0; i < items.Count; i++) { if (i > 0) { stringBuilder.Append(','); } stringBuilder.Append(JsonStr(items[i])); } stringBuilder.Append(']'); return stringBuilder.ToString(); } private static string JsonStr(string s) { if (s == null) { return "\"\""; } StringBuilder stringBuilder = new StringBuilder(s.Length + 2); stringBuilder.Append('"'); foreach (char c in s) { switch (c) { case '"': stringBuilder.Append("\\\""); continue; case '\\': stringBuilder.Append("\\\\"); continue; case '\n': stringBuilder.Append("\\n"); continue; case '\r': stringBuilder.Append("\\r"); continue; case '\t': stringBuilder.Append("\\t"); continue; } if (c < ' ') { StringBuilder stringBuilder2 = stringBuilder.Append("\\u"); int num = c; stringBuilder2.Append(num.ToString("x4", CultureInfo.InvariantCulture)); } else { stringBuilder.Append(c); } } stringBuilder.Append('"'); return stringBuilder.ToString(); } } internal static class EnemyResolver { private static readonly string[] _turretMarkers = new string[3] { "ToilHeadController", "MantiToilController", "TurretHeadController" }; private static readonly string[] _slayerMarkers = new string[3] { "ToilSlayerController", "MantiSlayerController", "SlayerController" }; public static string Resolve(object enemyAiObj) { string baseName = GetBaseName(enemyAiObj); if (string.IsNullOrEmpty(baseName)) { return null; } try { switch (TurretKind(enemyAiObj)) { case 2: return baseName + "+Turret+Slayer"; case 1: return baseName + "+Turret"; } } catch { } return baseName; } private static string GetBaseName(object enemyAiObj) { try { EnemyAI val = (EnemyAI)((enemyAiObj is EnemyAI) ? enemyAiObj : null); if ((Object)(object)val != (Object)null && (Object)(object)val.enemyType != (Object)null && !string.IsNullOrEmpty(val.enemyType.enemyName)) { return val.enemyType.enemyName; } } catch { } return null; } private static int TurretKind(object enemyAiObj) { MonoBehaviour val = (MonoBehaviour)((enemyAiObj is MonoBehaviour) ? enemyAiObj : null); if ((Object)(object)val == (Object)null) { return 0; } Component[] componentsInChildren = ((Component)val).GetComponentsInChildren<Component>(true); if (componentsInChildren == null) { return 0; } int num = 0; Component[] array = componentsInChildren; foreach (Component val2 in array) { if ((Object)(object)val2 == (Object)null) { continue; } string name = ((object)val2).GetType().Name; if (string.IsNullOrEmpty(name)) { continue; } string[] slayerMarkers = _slayerMarkers; foreach (string value in slayerMarkers) { if (name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return 2; } } if (num != 0) { continue; } slayerMarkers = _turretMarkers; foreach (string value2 in slayerMarkers) { if (name.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0) { num = 1; break; } } } return num; } } [HarmonyPatch(typeof(DepositItemsDesk), "SellAndDisplayItemProfits")] internal static class Patch_DepositItemsDesk_Sell { [HarmonyPrefix] public static void Prefix(int profit) { try { if (profit > 0) { RunStats.AddSold(profit); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[sold] продано на {profit} (всего за забег: {RunStats.SoldTotal})"); } } catch { } } } [HarmonyPatch] internal static class Patch_EnemyAI_HitEnemy { [HarmonyTargetMethods] internal static IEnumerable<MethodBase> Targets() { List<MethodBase> list = new List<MethodBase>(); MethodInfo methodInfo = AccessTools.Method(typeof(EnemyAI), "HitEnemy", (Type[])null, (Type[])null); if (methodInfo != null) { list.Add(methodInfo); } try { Type[] types = typeof(EnemyAI).Assembly.GetTypes(); foreach (Type type in types) { if (!(type == null) && type.IsSubclassOf(typeof(EnemyAI))) { MethodInfo methodInfo2 = null; try { methodInfo2 = type.GetMethod("HitEnemy", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { } if (methodInfo2 != null && !methodInfo2.IsAbstract) { list.Add(methodInfo2); } } } } catch { } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[hit] патчим HitEnemy: {list.Count} методов (база + переопределения)."); } return list; } [HarmonyPostfix] public static void Postfix(EnemyAI __instance, int force) { try { if (!((Object)(object)__instance == (Object)null) && force > 0) { MonsterState.MarkHurt(((Object)__instance).GetInstanceID()); string text = null; try { text = EnemyResolver.Resolve(__instance); } catch { } if (!string.IsNullOrEmpty(text)) { OverlayManager.Instance?.FlashMonster(text, __instance.isOutside); } } } catch { } } } [HarmonyPatch(typeof(StartMatchLever), "PullLever")] internal static class Patch_StartMatchLever_PullLever { [HarmonyPostfix] public static void Postfix() { try { RunSnapshot.OnLeverPulled(); OverlayManager.Instance?.HideAnalytics(); } catch { } } } internal static class RunSnapshot { public static string LastRunJson { get; private set; } public static bool ShowLastRun { get; private set; } public static void CaptureRunEnd() { try { LastRunJson = RunStats.ToJson(); ShowLastRun = true; GameState.BumpResetToken(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[run] забег завершён — аналитика сохранена, таймер сброшен."); } } catch { } } public static void OnLeverPulled() { if (ShowLastRun || LastRunJson != null) { ShowLastRun = false; LastRunJson = null; RunStats.ResetRun(); GameState.ResetDeaths(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[run] рычаг — статистика забега сброшена, начинаем новый."); } } } public static void ResetForNewSave() { ShowLastRun = false; LastRunJson = null; GameState.ResetDeaths(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[run] новый сейв — статистика и таймер обнулены."); } } } internal static class GameExtras { private const float AdMaxSeconds = 14f; private static float _adStarted = -1f; private static bool _mdSearched; private static Type _mdHandlerType; private static PropertyInfo _mdTimeLeft; private static PropertyInfo _mdStartedApi; private static bool _multSearched; private static FieldInfo _bcmeMulField; private static FieldInfo _bcmeMulNetField; private static PropertyInfo _bcmeMulNetInstance; private static PropertyInfo _bcmeMulNetValue; private static MethodInfo _wrGetCurrent; private static PropertyInfo _wrScrapEnabled; private static PropertyInfo _weatherScrapProp; private const BindingFlags F = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const float NearDoor = 14f; private static int _lastDoorId = int.MinValue; private static bool _lastDoorSide; public static bool PopupActive() { try { HUDManager instance = HUDManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (IsAnimatorShowing(instance.endgameStatsAnimator, "display", "displayStats", "showStats")) { return true; } if (IsAnimatorShowing(instance.globalNotificationAnimator, "display", "displayNotification")) { return true; } if (GetFloat(instance, "displayTipTextTimer") > 0.05f) { return true; } } catch { } return false; } public static bool StoreAdActive() { try { HUDManager instance = HUDManager.Instance; if ((Object)(object)instance == (Object)null) { _adStarted = -1f; return false; } bool num = IsAnimatorShowing(instance.advertAnimator, "display", "displayAd", "showAd"); bool flag = (Object)(object)instance.advertAnimator != (Object)null && ((Component)instance.advertAnimator).gameObject.activeInHierarchy; if (num || flag) { if (_adStarted < 0f) { _adStarted = Time.unscaledTime; } if (Time.unscaledTime - _adStarted > 14f) { return false; } return true; } _adStarted = -1f; } catch { _adStarted = -1f; } return false; } public static int SecondsToEndOfDay() { try { TimeOfDay instance = TimeOfDay.Instance; StartOfRound instance2 = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || !instance2.shipHasLanded) { return -1; } float totalTime = instance.totalTime; if (totalTime <= 0f) { return -1; } float num = instance.normalizedTimeOfDay; if (num < 0f) { num = Mathf.Clamp01(instance.currentDayTime / totalTime); } float num2 = 1f; float shipLeaveAutomaticallyTime = instance.shipLeaveAutomaticallyTime; if (shipLeaveAutomaticallyTime > 0f && shipLeaveAutomaticallyTime <= 1f) { num2 = shipLeaveAutomaticallyTime; } float num3 = num2 - num; if (num3 <= 0f) { return 0; } float num4 = Mathf.Max(0.0001f, instance.globalTimeSpeedMultiplier); float num5 = totalTime / num4; int num6 = Mathf.RoundToInt(num3 * num5); num6 = Mathf.Clamp(num6, 0, 86400); int num7 = MeltdownSecondsLeft(); if (num7 >= 0 && num7 < num6) { num6 = num7; } return num6; } catch { return -1; } } public static int MeltdownSecondsLeft() { try { if (!_mdSearched) { _mdSearched = true; _mdHandlerType = GameState.FindTypeFuzzy("FacilityMeltdown", new string[1] { "MeltdownHandler" }); if (_mdHandlerType != null) { _mdTimeLeft = _mdHandlerType.GetProperty("TimeLeftUntilMeltdown", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } Type type = GameState.FindTypeFuzzy("FacilityMeltdown", new string[1] { "MeltdownAPI" }); if (type != null) { _mdStartedApi = type.GetProperty("MeltdownStarted", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[meltdown] handler=" + ((_mdHandlerType != null) ? "OK" : "нет") + ", TimeLeftUntilMeltdown=" + ((_mdTimeLeft != null) ? "OK" : "нет"))); } } if (_mdHandlerType == null || _mdTimeLeft == null) { return -1; } if (_mdStartedApi != null) { object value = _mdStartedApi.GetValue(null); if (value is bool && !(bool)value) { return -1; } } Object val = Object.FindObjectOfType(_mdHandlerType); if (val == (Object)null) { return -1; } if (!(_mdTimeLeft.GetValue(val) is float num) || num < 0f) { return -1; } return Mathf.Clamp(Mathf.RoundToInt(num), 0, 86400); } catch { return -1; } } public static bool ApparatusInside() { try { LungProp[] array = Object.FindObjectsOfType<LungProp>(); if (array == null || array.Length == 0) { return false; } LungProp[] array2 = array; foreach (LungProp val in array2) { if (!((Object)(object)val == (Object)null)) { if (val.isLungPowered) { return true; } GrabbableObject val2 = (GrabbableObject)(object)val; if ((Object)(object)val2 != (Object)null && val2.isInFactory && !val2.isHeld) { return true; } } } } catch { } return false; } private static float WeatherScrapMultiplier() { try { if (_wrGetCurrent == null) { return -1f; } if (_wrScrapEnabled != null) { object value = _wrScrapEnabled.GetValue(null); if (value is bool && !(bool)value) { return -1f; } } StartOfRound instance = StartOfRound.Instance; SelectableLevel val = (((Object)(object)instance != (Object)null) ? instance.currentLevel : null); if ((Object)(object)val == (Object)null) { return -1f; } object obj = _wrGetCurrent.Invoke(null, new object[1] { val }); if (obj == null) { return -1f; } if (_weatherScrapProp == null || _weatherScrapProp.DeclaringType != obj.GetType()) { _weatherScrapProp = obj.GetType().GetProperty("ScrapValueMultiplier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (_weatherScrapProp == null) { return -1f; } return (_weatherScrapProp.GetValue(obj) is float num) ? num : (-1f); } catch { return -1f; } } public static float LootMultiplier() { float num = 1f; try { if (!_multSearched) { _multSearched = true; _bcmeMulField = FindStaticFloatFieldInAssembly("BrutalCompany", new string[1] { "Manager" }, new string[1] { "scrapValueMultiplier" }); Type type = GameState.FindTypeByFullName("WeatherRegistry.WeatherManager") ?? GameState.FindTypeFuzzy("WeatherRegistry", new string[1] { "WeatherManager" }); if (type != null) { _wrGetCurrent = type.GetMethod("GetCurrentWeather", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(SelectableLevel) }, null); } Type type2 = GameState.FindTypeFuzzy("WeatherRegistry", new string[1] { "Settings" }); if (type2 != null) { _wrScrapEnabled = type2.GetProperty("ScrapMultipliers", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } try { Type type3 = GameState.FindTypeByFullName("BrutalCompanyMinus.Net") ?? GameState.FindTypeFuzzy("BrutalCompany", new string[1] { "Net" }); if (type3 != null) { _bcmeMulNetInstance = type3.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] fields = type3.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { string text = fieldInfo.Name.ToLowerInvariant(); if (text.Contains("mult") && (text.Contains("scrap") || text.Contains("value") || text.Contains("loot")) && fieldInfo.FieldType.Name.StartsWith("NetworkVariable")) { _bcmeMulNetField = fieldInfo; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[loot-mult] сетевой множитель BCME: Net." + fieldInfo.Name)); } break; } } } } catch { } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[loot-mult] BCME-поле=" + ((_bcmeMulField != null) ? (_bcmeMulField.DeclaringType?.Name + "." + _bcmeMulField.Name) : "не найдено") + ", WeatherRegistry.GetCurrentWeather=" + ((_wrGetCurrent != null) ? "OK" : "не найден"))); } } float num2 = BcmeMultiplier(); if (num2 > 0f) { num += num2 - 1f; } float num3 = WeatherScrapMultiplier(); if (num3 > 0f) { num += num3 - 1f; } } catch { } return Mathf.Clamp(num, 0f, 100f); } private static float BcmeMultiplier() { try { if (_bcmeMulNetField != null && _bcmeMulNetInstance != null) { object value = _bcmeMulNetInstance.GetValue(null); if (value != null) { object value2 = _bcmeMulNetField.GetValue(value); if (value2 != null) { if (_bcmeMulNetValue == null) { _bcmeMulNetValue = value2.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); } if (((_bcmeMulNetValue != null) ? _bcmeMulNetValue.GetValue(value2) : null) is float num && num > 0f) { return num; } } } } } catch { } try { if (_bcmeMulField != null && _bcmeMulField.GetValue(null) is float num2 && num2 > 0f) { return num2; } } catch { } return -1f; } private static FieldInfo FindStaticFloatFieldInAssembly(string asmContains, string[] typeNames, string[] fieldNames) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if ((assembly.GetName().Name ?? "").IndexOf(asmContains, StringComparison.OrdinalIgnoreCase) < 0) { continue; } Type[] array; Type[] types; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { List<Type> list = new List<Type>(); types = ex.Types; foreach (Type type in types) { if (type != null) { list.Add(type); } } array = list.ToArray(); } types = array; foreach (Type type2 in types) { bool flag = false; string[] array2 = typeNames; foreach (string b in array2) { if (string.Equals(type2.Name, b, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } if (!flag) { continue; } array2 = fieldNames; foreach (string name in array2) { try { FieldInfo field = type2.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(float)) { return field; } } catch { } } } } } catch { } return null; } private static bool IsAnimatorShowing(Animator anim, params string[] boolParams) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 try { if ((Object)(object)anim == (Object)null || !((Component)anim).gameObject.activeInHierarchy) { return false; } AnimatorControllerParameter[] parameters = anim.parameters; foreach (AnimatorControllerParameter val in parameters) { if ((int)val.type != 4) { continue; } foreach (string b in boolParams) { if (string.Equals(val.name, b, StringComparison.OrdinalIgnoreCase) && anim.GetBool(val.nameHash)) { return true; } } } } catch { } return false; } private static object GetObj(object o, string name) { try { if (o == null) { return null; } FieldInfo field = o.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(o); } PropertyInfo property = o.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { return property.GetValue(o); } } catch { } return null; } private static float GetFloat(object o, string name) { object obj = GetObj(o, name); if (obj is float) { return (float)obj; } return 0f; } public static bool DoorProbe(Vector3 playerPos, out Vector3 otherSide, out bool otherSideIsInside) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_0059: 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_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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) otherSide = Vector3.zero; otherSideIsInside = false; try { EntranceTeleport[] array = Object.FindObjectsOfType<EntranceTeleport>(); if (array == null || array.Length == 0) { return false; } EntranceTeleport val = null; float num = 196f; EntranceTeleport[] array2 = array; foreach (EntranceTeleport val2 in array2) { if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = (((Object)(object)val2.entrancePoint != (Object)null) ? val2.entrancePoint.position : ((Component)val2).transform.position) - playerPos; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val = val2; } } } if ((Object)(object)val == (Object)null) { return false; } array2 = array; foreach (EntranceTeleport val4 in array2) { if ((Object)(object)val4 == (Object)null || (Object)(object)val4 == (Object)(object)val || val4.entranceId != val.entranceId || val4.isEntranceToBuilding == val.isEntranceToBuilding) { continue; } otherSide = (((Object)(object)val4.entrancePoint != (Object)null) ? val4.entrancePoint.position : ((Component)val4).transform.position); otherSideIsInside = val.isEntranceToBuilding; if (_lastDoorId != val.entranceId || _lastDoorSide != val.isEntranceToBuilding) { _lastDoorId = val.entranceId; _lastDoorSide = val.isEntranceToBuilding; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[door] у двери id={val.entranceId} " + "(" + (val.isEntranceToBuilding ? "вход внутрь" : "выход наружу") + "), " + $"смотрим за неё в радиусе {ConfigSettings.DoorRadarRadius.Value:0} м.")); } } return true; } } catch { } return false; } } public static class GameState { private static int _deaths = 0; private static readonly HashSet<int> _deadThisRound = new HashSet<int>(); private static int _resetToken = 0; private static int _deathsBaseline; private static bool _baselineSet; private static int _deathsShown; private static int _deathsPending; private static bool _wasOnMoonDeaths; private static readonly Dictionary<string, int> _killerCounts = new Dictionary<string, int>(); private static readonly Dictionary<string, int> _eventDeaths = new Dictionary<string, int>(); private static readonly Dictionary<string, int> _monsterSeen = new Dictionary<string, int>(); private static Type _mgSpawnerType; private static bool _mgSearched; private static FieldInfo _mgOwnedField; private static PropertyInfo _mgInstanceProp; private static FieldInfo _mgInstanceField; private static Type _grabTurret; private static Type _grabMine; private static bool _grabSearched; private static int _landedScrap; private static bool _wasLanded; private static bool _scrapLocked; private static float _scrapSettleUntil; private const float ScrapSettleSeconds = 20f; private static Type _emType; private static FieldInfo _curEventsField; private static bool _bcSearched; private static readonly Dictionary<Type, MethodInfo> _nameMethodCache = new Dictionary<Type, MethodInfo>(); private static Type _wtVarsType; private static MethodInfo _wtGetCurrent; private static bool _wtSearched; private static float _lastLootLog; private static int _lastInside = -1; private static int _lastOutside = -1; public static int GetResetToken() { return _resetToken; } public static void BumpResetToken() { _resetToken++; } public static void RegisterDeath(PlayerControllerB p, string killer = null) { bool flag = false; try { int item = (int)p.playerClientId; if (_deadThisRound.Add(item)) { _deaths++; flag = true; } } catch { _deaths++; flag = true; } if (!flag) { return; } try { if (!string.IsNullOrEmpty(killer)) { _killerCounts.TryGetValue(killer, out var value); _killerCounts[killer] = value + 1; } string brutalEvent = GetBrutalEvent(); if (!string.IsNullOrEmpty(brutalEvent) && brutalEvent != "—") { _eventDeaths.TryGetValue(brutalEvent, out var value2); _eventDeaths[brutalEvent] = value2 + 1; } RunStats.OnDeath(killer); } catch { } } public static void OnNewRound() { _deadThisRound.Clear(); } public static void ResetDeaths() { _deaths = 0; _deadThisRound.Clear(); _baselineSet = false; _deathsShown = 0; _deathsPending = 0; _resetToken++; _killerCounts.Clear(); _eventDeaths.Clear(); _monsterSeen.Clear(); RunStats.ResetRun(); } public static int GetDeaths() { try { int num = _deaths; if (ConfigSettings.TeamDeaths.Value) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && instance.gameStats != null) { int num2 = Mathf.Max(instance.gameStats.deaths, 0); if (!_baselineSet) { _deathsBaseline = num2; _baselineSet = true; } if (num2 < _deathsBaseline) { _deathsBaseline = num2; } num = num2 - _deathsBaseline; } } _deathsPending = num; if (!ConfigSettings.DeathsOnlyOnLeave.Value) { _deathsShown = num; return _deathsShown; } bool onMoon = GetOnMoon(); if (_wasOnMoonDeaths && !onMoon) { _deathsShown = _deathsPending; } _wasOnMoonDeaths = onMoon; return _deathsShown; } catch { return _deaths; } } public static void TickStats() { try { HashSet<string> hashSet = new HashSet<string>(); foreach (EnemyAI allLiveEnemy in GetAllLiveEnemies()) { if (!((Object)(object)allLiveEnemy == (Object)null) && !allLiveEnemy.isEnemyDead) { string text = EnemyResolver.Resolve(allLiveEnemy); if (text != null) { hashSet.Add(text); } } } foreach (string item in hashSet) { _monsterSeen.TryGetValue(item, out var value); _monsterSeen[item] = value + 1; } } catch { } } private static string TopOf(Dictionary<string, int> dict) { string result = null; int num = 0; foreach (KeyValuePair<string, int> item in dict) { if (item.Value > num) { num = item.Value; result = item.Key; } } return result; } public static string GetTopKiller() { return TopOf(_killerCounts); } public static string GetTopMonster() { return TopOf(_monsterSeen); } public static string GetDeadliestEvent() { return TopOf(_eventDeaths); } public static (int alive, int total) GetCrew() { try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return (alive: 0, total: 0); } int num = 0; int num2 = 0; PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && (val.isPlayerControlled || val.isPlayerDead)) { num++; if (!val.isPlayerDead) { num2++; } } } if (num == 0) { num = 1; } return (alive: num2, total: num); } catch { return (alive: 0, total: 0); } } public static int GetLocalHealth() { try { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return 0; } return val.health; } catch { return 0; } } private static void EnsureMonstersGordion() { if (_mgSearched) { return; } _mgSearched = true; _mgSpawnerType = FindTypeByFullName("MonstersGordion.CompanyMonsterSpawner") ?? FindTypeFuzzy("MonstersGordion", new string[1] { "CompanyMonsterSpawner" }); if (_mgSpawnerType != null) { _mgOwnedField = _mgSpawnerType.GetField("_ownedEnemies", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? _mgSpawnerType.GetField("ownedEnemies", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _mgInstanceProp = _mgSpawnerType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); _mgInstanceField = _mgSpawnerType.GetField("Instance", BindingFlags.Static | BindingFlags.Public); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[reflection] MonstersGordion=" + _mgSpawnerType.FullName + ", _ownedEnemies=" + ((_mgOwnedField != null) ? "OK" : "НЕ НАЙДЕНО"))); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[reflection] MonstersGordion не найден (не установлен?)"); } } } public static List<EnemyAI> GetGordionEnemies() { List<EnemyAI> list = new List<EnemyAI>(); try { EnsureMonstersGordion(); if (_mgSpawnerType == null || _mgOwnedField == null) { return list; } object obj = _mgInstanceProp?.GetValue(null) ?? _mgInstanceField?.GetValue(null) ?? GetSingletonInstance(_mgSpawnerType); if (obj == null) { return list; } if (!(_mgOwnedField.GetValue(obj) is IEnumerable enumerable)) { return list; } foreach (object item in enumerable) { EnemyAI val = (EnemyAI)((item is EnemyAI) ? item : null); if (val != null && (Object)(object)val != (Object)null && !val.isEnemyDead) { list.Add(val); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("GetGordionEnemies fail: " + ex.Message)); } } return list; } public static List<EnemyAI> GetAllLiveEnemies() { List<EnemyAI> list = new List<EnemyAI>(); HashSet<int> hashSet = new HashSet<int>(); try { RoundManager instance = RoundManager.Instance; if ((Object)(object)instance != (Object)null && instance.SpawnedEnemies != null) { foreach (EnemyAI spawnedEnemy in instance.SpawnedEnemies) { if ((Object)(object)spawnedEnemy != (Object)null && !spawnedEnemy.isEnemyDead && hashSet.Add(((Object)spawnedEnemy).GetInstanceID())) { list.Add(spawnedEnemy); } } } } catch { } foreach (EnemyAI gordionEnemy in GetGordionEnemies()) { if ((Object)(object)gordionEnemy != (Object)null && !gordionEnemy.isEnemyDead && hashSet.Add(((Object)gordionEnemy).GetInstanceID())) { list.Add(gordionEnemy); } } return list; } public static (List<string> outside, List<string> inside) GetMonsters() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) //IL_0082: 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_0146: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); List<string> list2 = new List<string>(); try { Dictionary<string, int> dictionary = new Dictionary<string, int>(); Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); Dictionary<string, float> dictionary3 = new Dictionary<string, float>(); Dictionary<string, float> dictionary4 = new Dictionary<string, float>(); Vector3 val = Vector3.zero; bool flag = false; try { PlayerControllerB val2 = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val2 != (Object)null) { val = ((Component)val2).transform.position; flag = true; } } catch { } Vector3 otherSide = Vector3.zero; bool flag2 = false; bool otherSideIsInside = false; float num = 0f; if (flag && Gate.DoorRadar) { flag2 = GameExtras.DoorProbe(val, out otherSide, out otherSideIsInside); num = Mathf.Clamp(Gate.DoorRadius, 5f, 60f); } foreach (EnemyAI allLiveEnemy in GetAllLiveEnemies()) { if ((Object)(object)allLiveEnemy == (Object)null || allLiveEnemy.isEnemyDead || !MonsterState.VisibleToLocal(allLiveEnemy)) { continue; } string text = "Unknown"; try { string text2 = EnemyResolver.Resolve(allLiveEnemy); if (!string.IsNullOrEmpty(text2)) { text = text2; } } catch { } text += MonsterState.TokensFor(allLiveEnemy); Dictionary<string, int> obj3 = (allLiveEnemy.isOutside ? dictionary : dictionary2); obj3.TryGetValue(text, out var value); obj3[text] = value + 1; if (!flag) { continue; } float num2 = Vector3.Distance(val, ((Component)allLiveEnemy).transform.position); if (flag2 && allLiveEnemy.isOutside != otherSideIsInside) { float num3 = Vector3.Distance(otherSide, ((Component)allLiveEnemy).transform.position); if (num3 <= num && num3 < num2) { num2 = num3; } } Dictionary<string, float> dictionary5 = (allLiveEnemy.isOutside ? dictionary3 : dictionary4); if (!dictionary5.TryGetValue(text, out var value2) || num2 < value2) { dictionary5[text] = num2; } } foreach (KeyValuePair<string, int> item in dictionary) { list.Add(Fmt(item.Key, item.Value, dictionary3)); } foreach (KeyValuePair<string, int> item2 in dictionary2) { list2.Add(Fmt(item2.Key, item2.Value, dictionary4)); } list.Sort(StringComparer.Ordinal); list2.Sort(StringComparer.Ordinal); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("GetMonsters fail: " + ex.Message)); } } return (outside: list, inside: list2); } private static string Fmt(string name, int count, Dictionary<string, float> dist) { string text = ((count > 1) ? $"{name} x{count}" : name); if (dist != null && dist.TryGetValue(name, out var value)) { text = text + " @" + Mathf.RoundToInt(value); } return text; } private static bool OnShip(Vector3 p) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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 { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } Vector3 val = p + Vector3.up * 0.25f; Bounds bounds; if ((Object)(object)instance.shipBounds != (Object)null) { bounds = instance.shipBounds.bounds; if (((Bounds)(ref bounds)).Contains(val)) { return true; } } if ((Object)(object)instance.shipInnerRoomBounds != (Object)null) { bounds = instance.shipInnerRoomBounds.bounds; if (((Bounds)(ref bounds)).Contains(val)) { return true; } } } catch { } return false; } public static List<string> GetTraps() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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) List<string> list = new List<string>(); Dictionary<string, List<Vector3>> pos; try { bool needScan = Gate.RequireScan; pos = new Dictionary<string, List<Vector3>>(); if (!_grabSearched) { _grabSearched = true; _grabTurret = FindTypeByFullName("BrutalCompanyMinus.Minus.MonoBehaviours.GrabbableTurret"); _grabMine = FindTypeByFullName("BrutalCompanyMinus.Minus.MonoBehaviours.GrabbableLandmine"); } CollectType<Turret>("Turret"); CollectType<Landmine>("Landmine"); CollectType<SpikeRoofTrap>("Spike Trap"); CollectGrabbable(_grabTurret, "Turret"); CollectGrabbable(_grabMine, "Landmine"); Vector3 val = Vector3.zero; bool flag = false; try { PlayerControllerB val2 = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val2 != (Object)null) { val = ((Component)val2).transform.position; flag = true; } } catch { } foreach (KeyValuePair<string, List<Vector3>> item in pos) { int count = item.Value.Count; string text = ((count > 1) ? $"{item.Key} x{count}" : item.Key); if (flag && count > 0) { float num = float.MaxValue; foreach (Vector3 item2 in item.Value) { float num2 = Vector3.Distance(val, item2); if (num2 < num) { num = num2; } } if (num < float.MaxValue) { text = text + " @" + Mathf.RoundToInt(num); } } list.Add(text); } void CollectGrabbable(Type t, string label) { //IL_0050: 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) try { if (!(t == null)) { Object[] array = Object.FindObjectsOfType(t); if (array != null) { Object[] array2 = array; foreach (Object obj2 in array2) { GrabbableObject val3 = (GrabbableObject)(object)((obj2 is GrabbableObject) ? obj2 : null); if (!((Object)(object)val3 == (Object)null) && !val3.isHeld && !val3.isHeldByEnemy && !val3.isInShipRoom && !OnShip(((Component)val3).transform.position) && (!needScan || !ScanRegistry.Scannable((Component)(object)val3) || ScanRegistry.HasFor((Component)(object)val3))) { Add(label, ((Component)val3).transform.position); } } } } } catch { } } void CollectType<T>(string label) where T : Component { //IL_0032: 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) try { T[] array = Object.FindObjectsOfType<T>(); if (array != null) { T[] array2 = array; foreach (T val3 in array2) { if (!((Object)(object)val3 == (Object)null) && !OnShip(((Component)val3).transform.position) && (!needScan || !ScanRegistry.Scannable((Component)(object)val3) || ScanRegistry.HasFor((Component)(object)val3))) { Add(label, ((Component)val3).transform.position); } } } } catch { } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("GetTraps fail: " + ex.Message)); } } return list; void Add(string label, Vector3 p) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!pos.TryGetValue(label, out var value)) { value = new List<Vector3>(); pos[label] = value; } value.Add(p); } } public static int GetLevelScrap() { try { RoundManager instance = RoundManager.Instance; if (GetOnMoon()) { if (!_wasLanded) { _wasLanded = true; _scrapLocked = false; _landedScrap = 0; _scrapSettleUntil = Time.unscaledTime + 20f; } if ((Object)(object)instance != (Object)null && !_scrapLocked) { int num = (int)instance.totalScrapValueInLevel; if (num > _landedScrap) { _landedScrap = num; } if (_landedScrap > 0 && Time.unscaledTime >= _scrapSettleUntil) { _scrapLocked = true; } } } else { _wasLanded = false; _scrapLocked = false; _landedScrap = 0; } return _landedScrap; } catch { return _landedScrap; } } private static string GetEventName(object ev) { Type type = ev.GetType(); if (!_nameMethodCache.TryGetValue(type, out var value)) { value = type.GetMethod("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); _nameMethodCache[type] = value; } if (value != null) { try { return value.Invoke(ev, null) as string; } catch { } } return ExtractName(ev); } public static string GetBrutalEvent() { try { if (!_bcSearched) { _bcSearched = true; _emType = FindTypeByFullName("BrutalCompanyMinus.Minus.EventManager") ?? FindTypeFuzzy("BrutalCompany", new string[1] { "EventManager" }); if (_emType != null) { _curEventsField = _emType.GetField("currentEvents", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[reflection] BCMER EventManager=" + _emType.FullName + ", currentEvents field=" + ((_curEventsField != null) ? "OK" : "НЕ НАЙДЕНО"))); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[reflection] BCMER EventManager не найден (мод выключен?)"); } } } List<string> list = new List<string>(); if (_curEventsField != null && _curEventsField.GetValue(null) is IEnumerable enumerable) { foreach (object item in enumerable) { if (item != null) { string eventName = GetEventName(item); if (!string.IsNullOrEmpty(eventName)) { list.Add(eventName); } } } } if (list.Count == 0 && OverlayNet.HasHostState && !string.IsNullOrEmpty(OverlayNet.HostEvents)) { string[] array = OverlayNet.HostEvents.Split(','); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } } if (list.Count == 0) { foreach (BcmerEvents.EventInfo item2 in BcmeClientEvents.Get()) { if (!string.IsNullOrEmpty(item2.Name)) { list.Add(item2.Name); } } } if (list.Count == 0) { return null; } return string.Join(", ", list); } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogDebug((object)("GetBrutalEvent fail: " + ex.Message)); } return null; } } public static string GetWeatherTweaksWeather() { try { if (!_wtSearched) { _wtSearched = true; _wtVarsType = FindTypeByFullName("WeatherTweaks.Variables") ?? FindTypeFuzzy("WeatherTweaks", new string[1] { "Variables" }); if (_wtVarsType != null) { _wtGetCurrent = _wtVarsType.GetMethod("GetCurrentWeather", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[reflection] WeatherTweaks Variables=" + _wtVarsType.FullName + ", GetCurrentWeather=" + ((_wtGetCurrent != null) ? "OK" : "НЕ НАЙДЕНО"))); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[reflection] WeatherTweaks Variables не найден (мод выключен?)"); } } } if (_wtGetCurrent == null) { return null; } object obj = _wtGetCurrent.Invoke(null, null); if (obj == null) { return null; } string text = ExtractName(obj); return string.IsNullOrEmpty(text) ? null : text; } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogDebug((object)("GetWeatherTweaks fail: " + ex.Message)); } return null; } } public static string GetVanillaWeather() { try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null) { return "None"; } return ((object)Unsafe.As<LevelWeatherType, LevelWeatherType>(ref instance.currentLevel.currentWeather)/*cast due to .constrained prefix*/).ToString(); } catch { return "None"; } } public static string GetMoonName() { try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null) { return "—"; } return instance.currentLevel.PlanetName; } catch { return "—"; } } public static bool GetOnMoon() { try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null) { return false; } return instance.shipHasLanded; } catch { return false; } } public static bool GetLoading() { try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } return instance.travellingToNewLevel; } catch { return false; } } public static bool GetInGame() { try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } return instance.shipHasLanded || instance.travellingToNewLevel; } catch { return false; } } public static int GetDayCount() { try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && instance.gameStats != null) { return instance.gameStats.daysSpent + 1; } TimeOfDay instance2 = TimeOfDay.Instance; if ((Object)(object)instance2 == (Object)null) { return 1; } return (instance2.daysUntilDeadline < 0) ? 1 : (3 - instance2.daysUntilDeadline); } catch { return 1; } } public static int GetQuotaIndexSafe() { try { TimeOfDay instance = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null) { return 1; } return instance.timesFulfilledQuota + 1; } catch { return 1; } } public static int GetShipScrapSafe() { try { int num = 0; GameObject[] array = GameObject.FindGameObjectsWithTag("PhysicsProp"); for (int i = 0; i < array.Length; i++) { GrabbableObject component = array[i].GetComponent<GrabbableObject>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.itemProperties == (Object)null) && component.itemProperties.isScrap && (component.isInShipRoom || component.isInElevator)) { num += component.scrapValue; } } return num; } catch { return 0; } } public static List<KeyValuePair<int, int>> GetShipScrapItems() { List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>(); try { GameObject[] array = GameObject.FindGameObjectsWithTag("PhysicsProp"); for (int i = 0; i < array.Length; i++) { GrabbableObject component = array[i].GetComponent<GrabbableObject>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.itemProperties == (Object)null) && component.itemProperties.isScrap && (component.isInShipRoom || component.isInElevator)) { list.Add(new KeyValuePair<int, int>(((Object)component).GetInstanceID(), component.scrapValue)); } } } catch { } return list; } public static List<KeyValuePair<int, string>> GetMonsterInstances() { List<KeyValuePair<int, string>> list = new List<KeyValuePair<int, string>>(); try { foreach (EnemyAI allLiveEnemy in GetAllLiveEnemies()) { if (!((Object)(object)allLiveEnemy == (Object)null) && !allLiveEnemy.isEnemyDead) { string text = EnemyResolver.Resolve(allLiveEnemy); if (text != null) { list.Add(new KeyValuePair<int, string>(((Object)allLiveEnemy).GetInstanceID(), text)); } } } } catch { } return list; } public static (List<string> outside, List<string> inside) GetMonstersRaw() { List<string> list = new List<string>(); List<string> list2 = new List<string>(); try { foreach (EnemyAI allLiveEnemy in GetAllLiveEnemies()) { if (!((Object)(object)allLiveEnemy == (Object)null) && !allLiveEnemy.isEnemyDead) { string text = EnemyResolver.Resolve(allLiveEnemy); if (text != null) { (allLiveEnemy.isOutside ? list : list2).Add(text); } } } } catch { } return (outside: list, inside: list2); } public static (int quota, int fulfilled) GetQuotaProgress() { try { TimeOfDay instance = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null) { return (quota: 0, fulfilled: 0); } return (quota: instance.profitQuota, fulfilled: instance.quotaFulfilled); } catch { return (quota: 0, fulfilled: 0); } } public static int GetDaysLeft() { try { TimeOfDay instance = TimeOfDay.Instance; return ((Object)(object)instance != (Object)null) ? instance.daysUntilDeadline : (-1); } catch { return -1; } } public static string GetInterior() { try { if (!GetOnMoon()) { return null; } DungeonFlow val = RoundManager.Instance?.dungeonGenerator?.Generator?.DungeonFlow; if ((Object)(object)val == (Object)null) { return null; } string text = ((Object)val).name ?? ""; if (text.IndexOf("Level1", StringComparison.OrdinalIgnoreCase) >= 0) { return "Facility"; } if (text.IndexOf("Level2", StringComparison.OrdinalIgnoreCase) >= 0) { return "Mansion"; } if (text.IndexOf("Level3", StringComparison.OrdinalIgnoreCase) >= 0) { return "Mineshaft"; } text = text.Replace("DungeonFlow", "").Replace("Flow", "").Replace("flow", "") .Trim(); return string.IsNullOrEmpty(text) ? null : text; } catch { return null; } } public static (int hives, int inside, int outside) GetLootBreakdown() { int num = 0; int num2 = 0; int num3 = 0; try { if (!GetOnMoon()) { return (hives: 0, inside: 0, outside: 0); } GameObject[] array = GameObject.FindGameObjectsWithTag("PhysicsProp"); for (int i = 0; i < array.Length; i++) { GrabbableObject component = array[i].GetComponent<GrabbableObject>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.itemProperties == (Object)null) && component.itemProperties.isScrap && !component.isInShipRoom && !component.isInElevator && !component.isHeld && !component.isHeldByEnemy) { if ((component.itemProperties.itemName ?? "").IndexOf("hive", StringComparison.OrdinalIgnoreCase) >= 0) { num++; } else if (component.isInFactory) { num2++; } else { num3++; } } } if (Time.time - _lastLootLog > 5f && (num2 != _lastInside || num3 != _lastOutside)) { _lastLootLog = Time.time; _lastInside = num2; _lastOutside = num3; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[loot] внутри={num2} снаружи={num3} ульи={num}"); } } } catch { } return (hives: num, inside: num2, outside: num3); } public static bool GetOldBird() { try { foreach (EnemyAI allLiveEnemy in GetAllLiveEnemies()) { if (!((Object)(object)allLiveEnemy == (Object)null) && !allLiveEnemy.isEnemyDead) { string text = (((Object)(object)allLiveEnemy.enemyType != (Object)null) ? (allLiveEnemy.enemyType.enemyName ?? "") : ""); if (text.IndexOf("RadMech", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Old Bird", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } } catch { } return false; } public static bool GetOnShip() { try { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; return (Object)(object)val != (Object)null && val.isInHangarShipRoom; } catch { return false; } } public static bool GetInsideFactorySafe() { try { PlayerControllerB val = StartOfRound.Instance?.localPlayerController; return (Object)(object)val != (Object)null && val.isInsideFactory; } catch { return false; } } internal static Type FindTypeByFullName(string fullName) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type type = null; try { type = assembly.GetType(fullName, throwOnError: false); } catch { } if (type != null) { return type; } } } catch { } return null; } internal static Type FindTypeFuzzy(string asmNameContains, string[] typeNameCandidates) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string text = assembly.GetName().Name ?? ""; if (text.IndexOf(asmNameContains, StringComparison.OrdinalIgnoreCase) < 0) { continue; } Type[] source; try { source = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { source = ex.Types.Where((Type t) => t != null).ToArray(); } foreach (string cand in typeNameCandidates) { Type type = source.FirstOrDefault((Type t) => string.Equals(t.Name, cand, StringComparison.OrdinalIgnoreCase)); if (type != null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[reflection] нашёл тип " + type.FullName + " в " + text)); } return type; } } } } catch (Exception ex2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("FindTypeFuzzy fail: " + ex2.Message)); } } return null; } private static object ReadStaticMember(Type t, string name) { try { FieldInfo field = t.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { if (field.IsStatic) { return field.GetValue(null); } object singletonInstance = GetSingletonInstance(t); if (singletonInstance != null) { return field.GetValue(singletonInstance); } } PropertyInfo property = t.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { MethodInfo? getMethod = property.GetGetMethod(nonPublic: true); if ((object)getMethod != null && getMethod.IsStatic) { return property.GetValue(null); } object singletonInstance2 = GetSingletonInstance(t); if (singletonInstance2 != null) { return property.GetValue(singletonInstance2); } } } catch { } return null; } private static object GetSingletonInstance(Type t) { try { PropertyInfo propertyInfo = t.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public) ?? t.GetProperty("instance", BindingFlags.Static | BindingFlags.Public); if (propertyInfo != null) { return propertyInfo.GetValue(null); } FieldInfo fieldInfo = t.GetField("Instance", BindingFlags.Static | BindingFlags.Public) ?? t.GetField("instance", BindingFlags.Static | BindingFlags.Public); if (fieldInfo != null) { return fieldInfo.GetValue(null); } } catch { } return null; } private static string ExtractName(object val) { if (val == null) { return null; } try { if (val is string result) { return result; } if (val.GetType().IsEnum) { return val.ToString(); } Type type = val.GetType(); PropertyInfo propertyInfo = type.GetProperty("Name") ?? type.GetProperty("name"); if (propertyInfo != null) { string text = propertyInfo.GetValue(val) as string; if (!string.IsNullOrEmpty(text)) { return text; } } FieldInfo fieldInfo = type.GetField("Name") ?? type.GetField("name"); if (fieldInfo != null) { string text2 = fieldInfo.GetValue(val) as string; if (!string.IsNullOrEmpty(text2)) { return text2; } } string text3 = val.ToString(); if (!string.IsNullOrEmpty(text3) && text3 != type.FullName && text3 != type.Name) { return text3; } } catch { } return null; } } internal static class MonsterState { private const float Interval = 0.5f; private static float _next; private static readonly Dictionary<int, string> _tokens = new Dictionary<int, string>(); private static readonly Dictionary<int, int> _hauntTarget = new Dictionary<int, int>(); private static readonly HashSet<int> _scanned = new HashSet<int>(); private static bool _loggedOnce; private const float HurtHold = 1.6f; private static readonly Dictionary<int, float> _hurt = new Dictionary<int, float>(); private static Terminal _terminal; private static readonly Dictionary<int, int> _scanIdCache = new Dictionary<int, int>(); private static readonly HashSet<int> _deviant = new HashSet<int>(); private static readonly Dictionary<int, float> _windMax = new Dictionary<int, float>(); private static readonly Dictionary<string, MemberInfo> _members = new Dictionary<string, MemberInfo>(); private const BindingFlags F = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public static void Reset() { _tokens.Clear(); _hauntTarget.Clear(); _scanned.Clear(); _scanIdCache.Clear(); _hurt.Clear(); _deviant.Clear(); _windMax.Clear(); _terminal = null; } public static void MarkHurt(int instanceId) { try { _hurt[instanceId] = Time.unscaledTime; _next = 0f; BridgeTicker.ForceImmediate(); } catch { } } private static bool IsScannedByBestiary(EnemyAI ai) { try { if ((Object)(object)_terminal == (Object)null) { _terminal = Object.FindObjectOfType<Terminal>(); } if ((Object)(object)_terminal == (Object)null || _terminal.scannedEnemyIDs == null) { return false; } int instanceID = ((Object)ai).GetInstanceID(); if (!_scanIdCache.TryGetValue(instanceID, out var value)) { value = -1; ScanNodeProperties componentInChildren = ((Component)ai).GetComponentInChildren<ScanNodeProperties>(true); if ((Object)(object)componentInChildren != (Object)null) { value = componentInChildren.creatureScanID; } _scanIdCache[instanceID] = value; } return value >= 0 && _terminal.scannedEnemyIDs.Contains(value); } catch { return false; } } public static void MarkScanned(int instanceId) { _scanned.Add(instanceId); } public static bool IsScanned(int instanceId) { return _scanned.Contains(instanceId); } public static string TokensFor(EnemyAI ai) { if ((Object)(object)ai == (Object)null) { return ""; } if (!_tokens.TryGetValue(((Object)ai).GetInstanceID(), out var value)) { return ""; } return value; } public static bool VisibleToLocal(EnemyAI ai) { try { if ((Object)(object)ai == (Object)null) { return true; } int instanceID = ((Object)ai).GetInstanceID(); if (!_hauntTarget.TryGetValue(instanceID, out var value)) { return true; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if ((Object)(object)val == (Object)null) { return false; } return value == ((Object)val).GetInstanceID(); } catch { return true; } } public static void Tick(List<EnemyAI> enemies) { try { if (Time.unscaledTime < _next) { return; } _next = Time.unscaledTime + 0.5f; if (enemies == null) { return; } _tokens.Clear(); _hauntTarget.Clear(); foreach (EnemyAI enemy in enemies) { if ((Object)(object)enemy == (Object)null || enemy.isEnemyDead) { continue; } string text = ((object)enemy).GetType().Name ?? ""; string text2 = ""; int num = 0; try { num = enemy.currentBehaviourStateIndex; } catch { } if (text.IndexOf("Hoarder", StringComparison.OrdinalIgnoreCase) >= 0) { if (GetBool(enemy, "isAngry") || GetBool(enemy, "inChase")) { text2 += "+Aggro"; } } else if (text.IndexOf("Jester", StringComparison.OrdinalIgnoreCase) >= 0) { int instanceID = ((Object)enemy).GetInstanceID(); if (num >= 2) { text2 += "+Angry"; _windMax.Remove(instanceID); } else if (num == 1) { float num2 = GetFloat(enemy, "popUpTimer"); if (!_windMax.TryGetValue(instanceID, out var value) || num2 > value) { value = num2; _windMax[instanceID] = value; } float num3 = ((value > 0.01f) ? Mathf.Clamp01(1f - num2 / value) : 0f); text2 = text2 + "+w" + Mathf.Clamp(Mathf.RoundToInt(num3 * 9f), 0, 9); } else { _windMax.Remove(instanceID); } } else if (text.IndexOf("CaveDweller", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Maneater", StringComparison.OrdinalIgnoreCase) >= 0) { bool flag = false; object obj2 = GetObj(enemy, "adultContainer"); GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null); if ((Object)(object)val != (Object)null) { flag = val.activeSelf; } if (!flag) { flag = GetBool(enemy, "adultMode", "grownUp", "isAdult"); } if (flag) { text2 += "+Adult"; } } else if (text.IndexOf("Nutcracker", StringComparison.OrdinalIgnoreCase) >= 0) { if (GetBool(enemy, "aimingGun") || GetBool(enemy, "isInspecting") || GetBool(enemy, "torsoTurning")) { text2 += "+Attack"; } } else if (text.IndexOf("Centipede", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("SnareFlea", StringComparison.OrdinalIgnoreCase) >= 0) { if (GetBool(enemy, "clingingToCeiling", "onCeiling", "hangingOnCeiling")) { text2 += "+Ceiling"; } } else if (text.IndexOf("SpringMan", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Coil", StringComparison.OrdinalIgnoreCase) >= 0) { bool flag2 = GetBool(enemy, "hasStopped", "stoppingMovement"); if (!flag2) { flag2 = AnyPlayerLookingAt(((Component)enemy).transform); } if (flag2) { text2 += "+Frozen"; } } else if (text.IndexOf("DressGirl", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("GhostGirl", StringComparison.OrdinalIgnoreCase) >= 0) { object obj3 = GetObj(enemy, "hauntingPlayer", "targetPlayer", "hauntedPlayer"); PlayerControllerB val2 = (PlayerControllerB)((obj3 is PlayerControllerB) ? obj3 : null); if ((Object)(object)val2 != (Object)null) { _hauntTarget[((Object)enemy).GetInstanceID()] = ((Object)val2).GetInstanceID(); } } if (IsTurretFiring(enemy)) { text2 += "+Firing"; } if (IsDeviant(enemy)) { text2 += "+Deviant"; } if (ConfigSettings.DamageFlash.Value && _hurt.TryGetValue(((Object)enemy).GetInstanceID(), out var value2) && Time.unscaledTime - value2 <= 1.6f) { text2 += "+Hurt"; } if ((!Gate.ResetScansDaily && IsScannedByBestiary(enemy)) || _scanned.Contains(((Object)enemy).GetInstanceID()) || ScanRegistry.HasFor((Component)(object)enemy)) { text2 += "+Scanned"; } if (text2.Length > 0) { _tokens[((Object)enemy).GetInstanceID()] = text2; } } if (_loggedOnce || _tokens.Count <= 0) { return; } _loggedOnce = true; StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<int, string> token in _tokens) { stringBuilder.Append(token.Value).Append(' '); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[states] первые состояния: " + stringBuilder)); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("MonsterState.Tick: " + ex.Message)); } } } private static bool IsDeviant(EnemyAI ai) { try { int instanceID = ((Object)ai).GetInstanceID(); if (_deviant.Contains(instanceID)) { return true; } Component[] componentsInChildren = ((Component)ai).GetComponentsInChildren<Component>(true); if (componentsInChildren == null) { return false; } Component[] array = componentsInChildren; foreach (Component val in array) { if (!((Object)(object)val == (Object)null) && string.Equals(((object)val).GetType().Name, "DeviantMarker", StringComparison.Ordinal)) { _deviant.Add(instanceID); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[deviant] " + ((object)ai).GetType().Name + " помечен как девиант — иконка перевёрнута.")); } BridgeTicker.ForceImmediate(); return true; } } } catch { } return false; } private static bool IsTurretFiring(EnemyAI ai) { try { Component[] componentsInChildren = ((Component)ai).GetComponentsInChildren<Component>(true); if (componentsInChildren == null) { return false; } Component[] array = componentsInChildren; foreach (Component val in array) { if ((Object)(object)val == (Object)null || ((object)val).GetType().Name.IndexOf("Turret", StringComparison.OrdinalIgnoreCase) < 0) { continue; } object obj = GetObj(val, "turretMode", "mode", "currentMode"); if (obj != null) { string text = obj.ToString(); if (text.IndexOf("Fir", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Berserk", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } } catch { } return false; } private static bool AnyPlayerLookingAt(Transform t) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)t == (Object)null) { return false; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null) { return false; } PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val == (Object)null || !val.isPlayerControlled || val.isPlayerDead) { continue; } Camera gameplayCamera = val.gameplayCamera; if (!((Object)(object)gameplayCamera == (Object)null)) { Vector3 val2 = t.position + Vector3.up * 1.2f - ((Component)gameplayCamera).transform.position; if (!(((Vector3)(ref val2)).magnitude > 40f) && Vector3.Dot(((Component)gameplayCamera).transform.forward, ((Vector3)(ref val2)).normalized) > 0.86f) { return true; } } } } catch { } return false; } private static MemberInfo FindMember(Type t, string[] names) { string key = t.FullName + "|" + string.Join(",", names); if (_members.TryGetValue(key, out var value)) { return value; } foreach (string name in names) { FieldInfo field = t.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { _members[key] = field; return field; } PropertyInfo property = t.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { _members[key] = property; return property; } } _members[key] = null; return null; } private static object GetObj(object o, params string[] names) { try { if (o == null) { return null; } MemberInfo memberInfo = FindMember(o.GetType(), names); FieldInfo fieldInfo = memberInfo as FieldInfo; if (fieldInfo != null) { return fieldInfo.GetValue(o); } PropertyInfo propertyInfo = memberInfo as PropertyInfo; if (propertyInfo != null) { return propertyInfo.GetValue(o); } } catch { } return null; } private static float GetFloat(object o, params string[] names) { object obj = GetObj(o, names); if (obj is float) { return (float)obj; }