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 Lifeline v0.2.0
plugins/Lifeline/Lifeline.dll
Decompiled a day 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Lc.Common; using LethalCompanyInputUtils.Api; using LethalNetworkAPI; using Lifeline.Core; using Lifeline.Patches; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("LethalCompanyInputUtils")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("thatumi")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0+860d7a915eb4bba7ae9e4014072e9ba7190ab209")] [assembly: AssemblyProduct("Lifeline")] [assembly: AssemblyTitle("Lifeline")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Lc.Common { internal static class FontProvider { private static TMP_FontAsset? _hudFont; internal static TMP_FontAsset? Get() { if ((Object)(object)_hudFont != (Object)null) { return _hudFont; } TMP_FontAsset val = ReflectionGuard.Run("FontProvider.HUD", delegate { HUDManager instance = HUDManager.Instance; return (!((Object)(object)instance != (Object)null) || !((Object)(object)instance.chatText != (Object)null)) ? null : ((TMP_Text)instance.chatText).font; }, null); if ((Object)(object)val != (Object)null) { _hudFont = val; return val; } TMP_FontAsset val2 = ReflectionGuard.Run("FontProvider.Default", () => TMP_Settings.defaultFontAsset, null); if ((Object)(object)val2 != (Object)null) { return val2; } TMP_FontAsset? obj = ReflectionGuard.Run("FontProvider.Any", () => Resources.FindObjectsOfTypeAll<TMP_FontAsset>().FirstOrDefault(), null); if ((Object)(object)obj == (Object)null) { Log.WarnOnce("FontProvider.none", "FontProvider: no TMP font available yet; text will use TMP defaults"); } return obj; } internal static void Invalidate() { _hudFont = null; } } internal enum LogKind { Debug, Info, Warning, Error } internal static class Log { private static readonly object Gate = new object(); private static readonly HashSet<string> OnceKeys = new HashSet<string>(StringComparer.Ordinal); private static Action<LogKind, string>? _sink; internal static bool DebugEnabled { get; set; } internal static void SetSink(Action<LogKind, string>? sink) { _sink = sink; } internal static void Debug(string message) { if (DebugEnabled) { Write(LogKind.Debug, message); } } internal static void Info(string message) { Write(LogKind.Info, message); } internal static void Warn(string message) { Write(LogKind.Warning, message); } internal static void Error(string message) { Write(LogKind.Error, message); } internal static bool WarnOnce(string key, string message) { if (!MarkOnce(key)) { return false; } Write(LogKind.Warning, message); return true; } internal static bool ErrorOnce(string key, string message) { if (!MarkOnce(key)) { return false; } Write(LogKind.Error, message); return true; } internal static bool MarkOnce(string key) { lock (Gate) { return OnceKeys.Add(key); } } internal static void ResetOnce() { lock (Gate) { OnceKeys.Clear(); } } private static void Write(LogKind kind, string message) { Action<LogKind, string> sink = _sink; try { if (sink != null) { sink(kind, message); } else { Console.WriteLine("[" + kind.ToString() + "] " + message); } } catch { } } } internal static class LogBepInEx { internal static void Init(ManualLogSource source) { Log.SetSink(delegate(LogKind kind, string message) { switch (kind) { case LogKind.Debug: source.LogDebug((object)message); break; case LogKind.Info: source.LogInfo((object)message); break; case LogKind.Warning: source.LogWarning((object)message); break; default: source.LogError((object)message); break; } }); } } internal static class ReflectionGuard { internal const BindingFlags AllMembers = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags Declared = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static readonly object Gate = new object(); private static readonly Dictionary<string, string> DisabledReasons = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<string, int> FailureCounts = new Dictionary<string, int>(StringComparer.Ordinal); private static readonly Dictionary<string, Type?> TypeCache = new Dictionary<string, Type>(StringComparer.Ordinal); internal static int MaxFailuresBeforeDisable { get; set; } = 25; internal static IReadOnlyDictionary<string, string> DisabledFeatures { get { lock (Gate) { return new Dictionary<string, string>(DisabledReasons, StringComparer.Ordinal); } } } internal static event Action<string, string>? FeatureDisabled; internal static bool IsEnabled(string feature) { lock (Gate) { return !DisabledReasons.ContainsKey(feature); } } internal static void Disable(string feature, string reason) { lock (Gate) { if (DisabledReasons.ContainsKey(feature)) { return; } DisabledReasons[feature] = reason; } Log.Warn("[" + feature + "] disabled: " + reason); try { ReflectionGuard.FeatureDisabled?.Invoke(feature, reason); } catch { } } internal static void Reset() { lock (Gate) { DisabledReasons.Clear(); FailureCounts.Clear(); TypeCache.Clear(); } } internal static Type? FindType(string fullName, string feature, string? assemblyName = null) { string key = (assemblyName ?? "*") + "|" + fullName; lock (Gate) { if (TypeCache.TryGetValue(key, out Type value) && value != null) { return value; } } Type type = null; try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assemblyName == null || string.Equals(assembly.GetName().Name, assemblyName, StringComparison.Ordinal)) { type = assembly.GetType(fullName, throwOnError: false); if (type != null) { break; } } } } catch (Exception ex) { Disable(feature, "type lookup " + fullName + " threw " + ex.GetType().Name + ": " + ex.Message); return null; } if (type != null) { lock (Gate) { TypeCache[key] = type; } } else { Disable(feature, "type " + fullName + ((assemblyName != null) ? (" (in " + assemblyName + ")") : "") + " not found"); } return type; } internal static FieldInfo? Field(Type? type, string name, string feature) { if (type == null) { Disable(feature, "field " + name + ": owner type is null"); return null; } Type type2 = type; while (type2 != null) { FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type2 = type2.BaseType; } Disable(feature, "field " + type.FullName + "." + name + " not found"); return null; } internal static MethodInfo? Method(Type? type, string name, Type[]? parameterTypes, string feature) { if (type == null) { Disable(feature, "method " + name + ": owner type is null"); return null; } Type type2 = type; while (type2 != null) { List<MethodInfo> list = (from m in type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == name select m).ToList(); if (list.Count != 0) { if (parameterTypes == null) { if (list.Count == 1) { return list[0]; } Disable(feature, "method " + type2.FullName + "." + name + " is ambiguous (" + list.Count + " overloads); pass parameter types"); return null; } foreach (MethodInfo item in list) { if (ParametersMatch(item.GetParameters(), parameterTypes)) { return item; } } } type2 = type2.BaseType; } Disable(feature, "method " + type.FullName + "." + name + Signature(parameterTypes) + " not found"); return null; } internal static PropertyInfo? Property(Type? type, string name, string feature) { if (type == null) { Disable(feature, "property " + name + ": owner type is null"); return null; } Type type2 = type; while (type2 != null) { PropertyInfo property = type2.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { return property; } type2 = type2.BaseType; } Disable(feature, "property " + type.FullName + "." + name + " not found"); return null; } internal static bool TryGet<T>(FieldInfo? field, object? instance, out T value, string feature) { value = default(T); if (field == null || !IsEnabled(feature)) { return false; } try { object value2 = field.GetValue(field.IsStatic ? null : instance); if (value2 is T val) { value = val; return true; } if (value2 == null && default(T) == null) { return true; } Log.WarnOnce(feature + "|type|" + field.Name, "[" + feature + "] field " + field.Name + " is " + (value2?.GetType().FullName ?? "null") + ", expected " + typeof(T).FullName); return false; } catch (Exception e) { CountFailure(feature, "get " + field.Name, e); return false; } } internal static bool TryGet<T>(PropertyInfo? property, object? instance, out T value, string feature) { value = default(T); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || methodInfo == null || !IsEnabled(feature)) { return false; } try { object value2 = property.GetValue(methodInfo.IsStatic ? null : instance, null); if (value2 is T val) { value = val; return true; } if (value2 == null && default(T) == null) { return true; } Log.WarnOnce(feature + "|type|" + property.Name, "[" + feature + "] property " + property.Name + " is " + (value2?.GetType().FullName ?? "null") + ", expected " + typeof(T).FullName); return false; } catch (Exception e) { CountFailure(feature, "get " + property.Name, e); return false; } } internal static bool TrySet(FieldInfo? field, object? instance, object? value, string feature) { if (field == null || !IsEnabled(feature)) { return false; } try { field.SetValue(field.IsStatic ? null : instance, value); return true; } catch (Exception e) { CountFailure(feature, "set " + field.Name, e); return false; } } internal static bool TryInvoke(MethodInfo? method, object? instance, object?[]? args, out object? result, string feature) { result = null; if (method == null || !IsEnabled(feature)) { return false; } try { result = method.Invoke(method.IsStatic ? null : instance, args); return true; } catch (TargetInvocationException ex) when (ex.InnerException != null) { CountFailure(feature, "invoke " + method.Name, ex.InnerException); return false; } catch (Exception e) { CountFailure(feature, "invoke " + method.Name, e); return false; } } internal static void Run(string key, Action body) { if (!IsEnabled(key)) { return; } try { body(); } catch (Exception e) { CountFailure(key, "threw", e); } } internal static T Run<T>(string key, Func<T> body, T fallback) { if (!IsEnabled(key)) { return fallback; } try { return body(); } catch (Exception e) { CountFailure(key, "threw", e); return fallback; } } internal static bool Prefix(string key, Func<bool> body) { return Run(key, body, fallback: true); } internal static int FailureCount(string key) { lock (Gate) { int value; return FailureCounts.TryGetValue(key, out value) ? value : 0; } } private static void CountFailure(string key, string what, Exception e) { int value; lock (Gate) { FailureCounts.TryGetValue(key, out value); value++; FailureCounts[key] = value; } if (value == 1) { Log.Error("[" + key + "] " + what + ": " + e); } if (value >= MaxFailuresBeforeDisable) { Disable(key, value + " exceptions (first logged above)"); } } private static bool ParametersMatch(ParameterInfo[] actual, Type[] expected) { if (actual.Length != expected.Length) { return false; } for (int i = 0; i < actual.Length; i++) { if (actual[i].ParameterType != expected[i]) { return false; } } return true; } private static string Signature(Type[]? parameterTypes) { if (parameterTypes != null) { return "(" + string.Join(", ", parameterTypes.Select((Type t) => t.Name)) + ")"; } return ""; } } internal static class TexGen { private delegate float CoverageFn(float x, float y); private static readonly Dictionary<string, Sprite> Cache = new Dictionary<string, Sprite>(); internal static Sprite RoundedRect(int radius = 12, int size = 0) { if (size <= 0) { size = radius * 2 + 4; } string key = "rr|" + radius + "|" + size; return Get(key, delegate { //IL_0054: 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_0093: Unknown result type (might be due to invalid IL or missing references) Texture2D obj = NewTexture(size, size, key); Paint(obj, (float x, float y) => TexGenMath.FillCoverage(TexGenMath.RoundedRectDistance(x, y, size, size, radius))); return Sprite.Create(obj, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)(radius + 1), (float)(radius + 1), (float)(radius + 1), (float)(radius + 1))); }); } internal static Sprite Outline(int radius = 12, int thickness = 2, int size = 0) { if (size <= 0) { size = radius * 2 + 4; } string key = "ol|" + radius + "|" + thickness + "|" + size; return Get(key, delegate { //IL_0068: 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_008b: Unknown result type (might be due to invalid IL or missing references) Texture2D obj = NewTexture(size, size, key); Paint(obj, (float x, float y) => TexGenMath.StrokeCoverage(TexGenMath.RoundedRectDistance(x, y, size, size, radius), thickness)); int num = Mathf.Max(radius, thickness) + 1; return Sprite.Create(obj, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)num, (float)num, (float)num, (float)num)); }); } internal static Sprite Circle(int diameter = 64, int thickness = 0) { string key = "ci|" + diameter + "|" + thickness; return Get(key, delegate { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) Texture2D obj = NewTexture(diameter, diameter, key); float r = (float)diameter * 0.5f; Paint(obj, delegate(float x, float y) { float distance = TexGenMath.CircleDistance(x, y, r, r, r - 0.5f); return (thickness <= 0) ? TexGenMath.FillCoverage(distance) : TexGenMath.StrokeCoverage(distance, thickness); }); return Sprite.Create(obj, new Rect(0f, 0f, (float)diameter, (float)diameter), new Vector2(0.5f, 0.5f), 100f); }); } internal static Sprite White() { return Get("white", delegate { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) Texture2D obj = NewTexture(1, 1, "white"); obj.SetPixel(0, 0, Color.white); obj.Apply(false, false); return Sprite.Create(obj, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f), 100f); }); } private static Sprite Get(string key, Func<Sprite> create) { if (Cache.TryGetValue(key, out Sprite value) && (Object)(object)value != (Object)null) { return value; } value = create(); ((Object)value).name = "LcTexGen_" + key; ((Object)value).hideFlags = (HideFlags)52; Cache[key] = value; return value; } private static Texture2D NewTexture(int w, int h, string key) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0031: Expected O, but got Unknown return new Texture2D(w, h, (TextureFormat)4, false) { name = "LcTexGen_" + key, wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1, hideFlags = (HideFlags)52 }; } private static void Paint(Texture2D tex, CoverageFn coverage) { //IL_005d: 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) int width = ((Texture)tex).width; int height = ((Texture)tex).height; Color32[] array = (Color32[])(object)new Color32[width * height]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { float num = coverage((float)j + 0.5f, (float)i + 0.5f); array[i * width + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)Mathf.RoundToInt(num * 255f)); } } tex.SetPixels32(array); tex.Apply(false, false); } } internal static class TexGenMath { internal static float RoundedRectDistance(float px, float py, float w, float h, float r) { r = Math.Max(0f, Math.Min(r, Math.Min(w, h) * 0.5f)); float num = w * 0.5f; float num2 = h * 0.5f; float val = Math.Abs(px - num) - (num - r); float num3 = Math.Abs(py - num2) - (num2 - r); float num4 = Math.Max(val, 0f); float num5 = Math.Max(num3, 0f); float num6 = (float)Math.Sqrt(num4 * num4 + num5 * num5); float num7 = Math.Min(Math.Max(val, num3), 0f); return num6 + num7 - r; } internal static float CircleDistance(float px, float py, float cx, float cy, float r) { float num = px - cx; float num2 = py - cy; return (float)Math.Sqrt(num * num + num2 * num2) - r; } internal static float FillCoverage(float distance) { return Clamp01(0.5f - distance); } internal static float StrokeCoverage(float distance, float thickness) { float num = FillCoverage(distance); float num2 = FillCoverage(distance + thickness); return Clamp01(num - num2); } internal static float Clamp01(float v) { if (!(v < 0f)) { if (!(v > 1f)) { return v; } return 1f; } return 0f; } } internal static class UiFactory { internal static class Theme { internal static Color PanelBg = new Color(0.05f, 0.05f, 0.06f, 0.92f); internal static Color PanelBorder = new Color(1f, 0.45f, 0.1f, 0.9f); internal static Color Text = new Color(0.98f, 0.62f, 0.25f, 1f); internal static Color TextDim = new Color(0.75f, 0.6f, 0.45f, 1f); internal static Color ButtonBg = new Color(0.16f, 0.09f, 0.05f, 0.95f); internal static Color ButtonHighlight = new Color(0.45f, 0.22f, 0.07f, 1f); internal static Color ButtonPressed = new Color(0.7f, 0.33f, 0.08f, 1f); internal static Color ButtonDisabled = new Color(0.12f, 0.12f, 0.12f, 0.7f); internal static Color Danger = new Color(0.9f, 0.18f, 0.15f, 1f); internal static Color BackdropColor = new Color(0f, 0f, 0f, 0.72f); internal static int CornerRadius = 10; internal static float FontSize = 26f; } internal static readonly Vector2 ReferenceResolution = new Vector2(1920f, 1080f); internal static Canvas Canvas(string name, int sortingOrder, bool dontDestroyOnLoad = false) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.layer = 5; if (dontDestroyOnLoad) { Object.DontDestroyOnLoad((Object)(object)val); } Canvas obj = val.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = sortingOrder; obj.pixelPerfect = false; CanvasScaler obj2 = val.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = ReferenceResolution; obj2.screenMatchMode = (ScreenMatchMode)0; obj2.matchWidthOrHeight = 0.5f; val.AddComponent<GraphicRaycaster>(); return obj; } internal static RectTransform Rect(Transform parent, string name) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }) { layer = 5 }.transform; ((Transform)val).SetParent(parent, false); return val; } internal static RectTransform Fill(RectTransform rt, float padding = 0f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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) rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.pivot = new Vector2(0.5f, 0.5f); rt.offsetMin = new Vector2(padding, padding); rt.offsetMax = new Vector2(0f - padding, 0f - padding); return rt; } internal static RectTransform Place(RectTransform rt, Vector2 anchor, Vector2 offset, Vector2 size, Vector2? pivot = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = anchor; rt.anchorMax = anchor; rt.pivot = pivot ?? anchor; rt.anchoredPosition = offset; rt.sizeDelta = size; return rt; } internal static RectTransform PlaceTL(RectTransform rt, float cx, float cy, float w, float h) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = new Vector2(0f, 1f); rt.anchorMax = new Vector2(0f, 1f); rt.pivot = new Vector2(0.5f, 0.5f); rt.anchoredPosition = new Vector2(cx, 0f - cy); rt.sizeDelta = new Vector2(w, h); return rt; } internal static LayoutElement Size(Component c, float width = -1f, float height = -1f, float flexibleWidth = -1f) { LayoutElement val = c.GetComponent<LayoutElement>(); if ((Object)(object)val == (Object)null) { val = c.gameObject.AddComponent<LayoutElement>(); } val.preferredWidth = width; val.preferredHeight = height; val.minHeight = height; val.flexibleWidth = flexibleWidth; return val; } internal static VerticalLayoutGroup Vertical(Component c, float spacing = 8f, int padding = 12) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown VerticalLayoutGroup obj = c.gameObject.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj).spacing = spacing; ((LayoutGroup)obj).padding = new RectOffset(padding, padding, padding, padding); ((LayoutGroup)obj).childAlignment = (TextAnchor)0; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; return obj; } internal static HorizontalLayoutGroup Horizontal(Component c, float spacing = 8f, int padding = 0) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown HorizontalLayoutGroup obj = c.gameObject.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj).spacing = spacing; ((LayoutGroup)obj).padding = new RectOffset(padding, padding, padding, padding); ((LayoutGroup)obj).childAlignment = (TextAnchor)3; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; return obj; } internal static Image Panel(Transform parent, string name, Color? color = null, bool border = true) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Fill(Rect(parent, name)); Image obj = ((Component)val).gameObject.AddComponent<Image>(); obj.sprite = TexGen.RoundedRect(Theme.CornerRadius); obj.type = (Type)1; ((Graphic)obj).color = (Color)(((??)color) ?? Theme.PanelBg); ((Graphic)obj).raycastTarget = true; if (border) { Image obj2 = ((Component)Fill(Rect((Transform)(object)val, "Border"))).gameObject.AddComponent<Image>(); obj2.sprite = TexGen.Outline(Theme.CornerRadius); obj2.type = (Type)1; ((Graphic)obj2).color = Theme.PanelBorder; ((Graphic)obj2).raycastTarget = false; } return obj; } internal static TextMeshProUGUI Text(Transform parent, string text, float size = 0f, TextAlignmentOptions align = (TextAlignmentOptions)513, Color? color = null, string name = "Text") { //IL_0047: 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_005a: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI val = ((Component)Rect(parent, name)).gameObject.AddComponent<TextMeshProUGUI>(); TMP_FontAsset val2 = FontProvider.Get(); if ((Object)(object)val2 != (Object)null) { ((TMP_Text)val).font = val2; } ((TMP_Text)val).text = text; ((TMP_Text)val).fontSize = ((size > 0f) ? size : Theme.FontSize); ((TMP_Text)val).alignment = align; ((Graphic)val).color = (Color)(((??)color) ?? Theme.Text); ((TMP_Text)val).enableWordWrapping = true; ((TMP_Text)val).overflowMode = (TextOverflowModes)1; ((Graphic)val).raycastTarget = false; return val; } internal static Button Button(Transform parent, string label, Action onClick, Vector2? size = null, string? name = null) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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) RectTransform obj = Rect(parent, name ?? ("Button_" + label)); obj.sizeDelta = (Vector2)(((??)size) ?? new Vector2(260f, 52f)); Image val = ((Component)obj).gameObject.AddComponent<Image>(); val.sprite = TexGen.RoundedRect(Theme.CornerRadius); val.type = (Type)1; ((Graphic)val).color = Color.white; Button val2 = ((Component)obj).gameObject.AddComponent<Button>(); ((Selectable)val2).targetGraphic = (Graphic)(object)val; ((Selectable)val2).colors = Colors(); ((UnityEvent)val2.onClick).AddListener(Guarded("Button " + label, onClick)); Fill(((TMP_Text)Text((Transform)(object)obj, label, 0f, (TextAlignmentOptions)514, null, "Label")).rectTransform, 6f); if (size.HasValue) { Size((Component)(object)val2, size.Value.x, size.Value.y); } return val2; } internal static Button CycleButton(Transform parent, Func<string> label, Action onClick, Vector2? size = null, string? name = null) { TextMeshProUGUI text = null; Button val = Button(parent, label(), delegate { onClick(); if ((Object)(object)text != (Object)null) { ((TMP_Text)text).text = label(); } }, size, name); text = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); return val; } internal static void SetLabel(Button button, string label) { TextMeshProUGUI componentInChildren = ((Component)button).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)componentInChildren).text = label; } } internal static Image Picture(Transform parent, string name, Sprite? sprite, Color color, bool raycast = false) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) Image obj = ((Component)Rect(parent, name)).gameObject.AddComponent<Image>(); obj.sprite = (Sprite)(((Object)(object)sprite != (Object)null) ? ((object)sprite) : ((object)TexGen.White())); ((Graphic)obj).color = color; ((Graphic)obj).raycastTarget = raycast; obj.preserveAspect = (Object)(object)sprite != (Object)null; return obj; } internal static Image Line(RectTransform parent, Vector2 from, Vector2 to, float thickness, Color color) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) Image obj = Picture((Transform)(object)parent, "Line", null, color); UiMath.Line(from.x, from.y, to.x, to.y, out var centreX, out var centreY, out var length, out var angleDeg); PlaceTL(((Graphic)obj).rectTransform, centreX, centreY, length, thickness); ((Transform)((Graphic)obj).rectTransform).localRotation = Quaternion.Euler(0f, 0f, angleDeg); return obj; } internal static RectTransform Backdrop(Transform parent, string name = "Backdrop", Color? color = null) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = Fill(Rect(parent, name)); Image obj2 = ((Component)obj).gameObject.AddComponent<Image>(); obj2.sprite = TexGen.White(); ((Graphic)obj2).color = (Color)(((??)color) ?? Theme.BackdropColor); ((Graphic)obj2).raycastTarget = true; return obj; } internal static Toggle Toggle(Transform parent, string label, bool value, Action<bool> onChanged, float height = 44f) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = Rect(parent, "Toggle_" + label); obj.sizeDelta = new Vector2(400f, height); Size((Component)(object)obj, -1f, height, 1f); Image val = ((Component)obj).gameObject.AddComponent<Image>(); val.sprite = TexGen.RoundedRect(Theme.CornerRadius); val.type = (Type)1; ((Graphic)val).color = Color.white; RectTransform obj2 = Place(Rect((Transform)(object)obj, "Box"), new Vector2(0f, 0.5f), new Vector2(8f, 0f), new Vector2(height - 12f, height - 12f)); Image obj3 = ((Component)obj2).gameObject.AddComponent<Image>(); obj3.sprite = TexGen.Outline(6); obj3.type = (Type)1; ((Graphic)obj3).color = Theme.Text; ((Graphic)obj3).raycastTarget = false; Image val2 = ((Component)Fill(Rect((Transform)(object)obj2, "Check"), 6f)).gameObject.AddComponent<Image>(); val2.sprite = TexGen.RoundedRect(4); val2.type = (Type)1; ((Graphic)val2).color = Theme.Text; ((Graphic)val2).raycastTarget = false; TextMeshProUGUI obj4 = Text((Transform)(object)obj, label, 0f, (TextAlignmentOptions)513, null, "Label"); ((TMP_Text)obj4).rectTransform.anchorMin = new Vector2(0f, 0f); ((TMP_Text)obj4).rectTransform.anchorMax = new Vector2(1f, 1f); ((TMP_Text)obj4).rectTransform.offsetMin = new Vector2(height + 4f, 0f); ((TMP_Text)obj4).rectTransform.offsetMax = new Vector2(-8f, 0f); Toggle obj5 = ((Component)obj).gameObject.AddComponent<Toggle>(); ((Selectable)obj5).targetGraphic = (Graphic)(object)val; obj5.graphic = (Graphic)(object)val2; ((Selectable)obj5).colors = Colors(transparentNormal: true); obj5.isOn = value; UnityAction<bool> val3 = Guarded("Toggle " + label, onChanged); ((UnityEvent<bool>)(object)obj5.onValueChanged).AddListener(val3); return obj5; } internal static ScrollRect ScrollList(Transform parent, string name, out RectTransform content, float spacing = 6f) { //IL_007d: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00e4: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = Fill(Rect(parent, name)); ScrollRect val = ((Component)obj).gameObject.AddComponent<ScrollRect>(); val.horizontal = false; val.vertical = true; val.movementType = (MovementType)2; val.scrollSensitivity = 30f; RectTransform val2 = Fill(Rect((Transform)(object)obj, "Viewport")); ((Component)val2).gameObject.AddComponent<RectMask2D>(); ((Graphic)((Component)val2).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0f); content = Rect((Transform)(object)val2, "Content"); content.anchorMin = new Vector2(0f, 1f); content.anchorMax = new Vector2(1f, 1f); content.pivot = new Vector2(0.5f, 1f); content.anchoredPosition = Vector2.zero; content.sizeDelta = Vector2.zero; ((LayoutGroup)Vertical((Component)(object)content, spacing, 4)).childAlignment = (TextAnchor)1; ContentSizeFitter obj2 = ((Component)content).gameObject.AddComponent<ContentSizeFitter>(); obj2.verticalFit = (FitMode)2; obj2.horizontalFit = (FitMode)0; val.viewport = val2; val.content = content; return val; } internal static void ScrollIntoView(ScrollRect scroll, RectTransform item) { ReflectionGuard.Run("UiFactory.ScrollIntoView", delegate { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) RectTransform content = scroll.content; RectTransform val = (RectTransform)(((Object)(object)scroll.viewport != (Object)null) ? ((object)scroll.viewport) : ((object)(RectTransform)((Component)scroll).transform)); if (!((Object)(object)content == (Object)null)) { Canvas.ForceUpdateCanvases(); Rect rect = content.rect; float height = ((Rect)(ref rect)).height; rect = val.rect; float height2 = ((Rect)(ref rect)).height; if (!(height <= height2)) { float y = ((Transform)content).InverseTransformPoint(((Transform)item).position).y; rect = item.rect; float num = 0f - (y + ((Rect)(ref rect)).height * (1f - item.pivot.y)); rect = item.rect; float num2 = num + ((Rect)(ref rect)).height; float num3 = content.anchoredPosition.y; if (num < num3) { num3 = num; } else if (num2 > num3 + height2) { num3 = num2 - height2; } num3 = Mathf.Clamp(num3, 0f, height - height2); content.anchoredPosition = new Vector2(content.anchoredPosition.x, num3); } } }); } internal static void LinkVertical(IList<Selectable> items, bool wrap = true, Selectable? left = null, Selectable? right = null) { Link(items, wrap, vertical: true, left, right); } internal static void LinkHorizontal(IList<Selectable> items, bool wrap = false, Selectable? up = null, Selectable? down = null) { Link(items, wrap, vertical: false, up, down); } internal static void Select(Selectable? target) { ReflectionGuard.Run("UiFactory.Select", delegate { EventSystem current = EventSystem.current; if (!((Object)(object)current == (Object)null) && !((Object)(object)target == (Object)null) && ((Component)target).gameObject.activeInHierarchy) { current.SetSelectedGameObject((GameObject)null); current.SetSelectedGameObject(((Component)target).gameObject); } }); } internal static void Destroy(Component? root) { if ((Object)(object)root != (Object)null) { Object.Destroy((Object)(object)root.gameObject); } } private static void Link(IList<Selectable> items, bool wrap, bool vertical, Selectable? sideA, Selectable? sideB) { //IL_00b4: 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_0118: Unknown result type (might be due to invalid IL or missing references) List<Selectable> list = new List<Selectable>(); foreach (Selectable item in items) { if ((Object)(object)item != (Object)null && ((Component)item).gameObject.activeInHierarchy && item.IsInteractable()) { list.Add(item); } } for (int i = 0; i < list.Count; i++) { Selectable val = ((i > 0) ? list[i - 1] : ((wrap && list.Count > 1) ? list[list.Count - 1] : null)); Selectable val2 = ((i < list.Count - 1) ? list[i + 1] : ((wrap && list.Count > 1) ? list[0] : null)); Navigation val3 = default(Navigation); ((Navigation)(ref val3)).mode = (Mode)4; Navigation navigation = val3; if (vertical) { ((Navigation)(ref navigation)).selectOnUp = val; ((Navigation)(ref navigation)).selectOnDown = val2; ((Navigation)(ref navigation)).selectOnLeft = sideA; ((Navigation)(ref navigation)).selectOnRight = sideB; } else { ((Navigation)(ref navigation)).selectOnLeft = val; ((Navigation)(ref navigation)).selectOnRight = val2; ((Navigation)(ref navigation)).selectOnUp = sideA; ((Navigation)(ref navigation)).selectOnDown = sideB; } list[i].navigation = navigation; } } private static ColorBlock Colors(bool transparentNormal = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) ColorBlock defaultColorBlock = ColorBlock.defaultColorBlock; ((ColorBlock)(ref defaultColorBlock)).normalColor = (Color)(transparentNormal ? new Color(0f, 0f, 0f, 0f) : Theme.ButtonBg); ((ColorBlock)(ref defaultColorBlock)).highlightedColor = Theme.ButtonHighlight; ((ColorBlock)(ref defaultColorBlock)).selectedColor = Theme.ButtonHighlight; ((ColorBlock)(ref defaultColorBlock)).pressedColor = Theme.ButtonPressed; ((ColorBlock)(ref defaultColorBlock)).disabledColor = Theme.ButtonDisabled; ((ColorBlock)(ref defaultColorBlock)).colorMultiplier = 1f; ((ColorBlock)(ref defaultColorBlock)).fadeDuration = 0.08f; return defaultColorBlock; } private static UnityAction Guarded(string key, Action action) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown return (UnityAction)delegate { ReflectionGuard.Run(key, action); }; } private static UnityAction<T> Guarded<T>(string key, Action<T> action) { return delegate(T v) { ReflectionGuard.Run(key, delegate { action(v); }); }; } } internal static class UiMath { internal static void Line(float fromX, float fromY, float toX, float toY, out float centreX, out float centreY, out float length, out float angleDeg) { float num = toX - fromX; float num2 = 0f - (toY - fromY); centreX = (fromX + toX) * 0.5f; centreY = (fromY + toY) * 0.5f; length = (float)Math.Sqrt(num * num + num2 * num2); angleDeg = ((length > 0f) ? ((float)(Math.Atan2(num2, num) * (180.0 / Math.PI))) : 0f); } } } namespace Lifeline { internal static class Hud { private static Canvas? _canvas; private static RectTransform? _root; private static TextMeshProUGUI? _text; private static Image? _fill; private static RectTransform? _bar; private static string? _toast; private static float _toastUntil; private static string? _shown; internal static void Prompt(string? text, float progress) { if (!Ensure()) { return; } string text2 = ((_toast != null && Time.realtimeSinceStartup < _toastUntil) ? _toast : null); string text3 = text2 ?? text; bool flag = text3 != null; if (((Component)_root).gameObject.activeSelf != flag) { ((Component)_root).gameObject.SetActive(flag); } if (flag) { if ((object)text3 != _shown) { _shown = text3; ((TMP_Text)_text).text = text3; } bool flag2 = text2 == null && progress > 0f; if (((Component)_bar).gameObject.activeSelf != flag2) { ((Component)_bar).gameObject.SetActive(flag2); } _fill.fillAmount = Mathf.Clamp01(progress); } } internal static void Toast(string text, float seconds) { _toast = text; _toastUntil = Time.realtimeSinceStartup + seconds; Prompt(text, 0f); } internal static void Hide() { if ((Object)(object)_root != (Object)null) { ((Component)_root).gameObject.SetActive(false); } } private static bool Ensure() { if ((Object)(object)_canvas != (Object)null) { return true; } return ReflectionGuard.Run("Lifeline.Hud", delegate { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) _canvas = UiFactory.Canvas("LifelineCanvas", 55, dontDestroyOnLoad: true); _root = UiFactory.Place(UiFactory.Rect(((Component)_canvas).transform, "Prompt"), new Vector2(0.5f, 0.36f), Vector2.zero, new Vector2(620f, 90f)); _text = UiFactory.Text((Transform)(object)_root, "", 26f, (TextAlignmentOptions)514, Color.white); UiFactory.Place(((TMP_Text)_text).rectTransform, new Vector2(0.5f, 1f), new Vector2(0f, -22f), new Vector2(620f, 44f)); ((TMP_Text)_text).richText = false; _bar = UiFactory.Place(UiFactory.Rect((Transform)(object)_root, "Bar"), new Vector2(0.5f, 0f), new Vector2(0f, 22f), new Vector2(320f, 14f)); Image obj = ((Component)_bar).gameObject.AddComponent<Image>(); obj.sprite = TexGen.White(); ((Graphic)obj).color = new Color(0f, 0f, 0f, 0.55f); ((Graphic)obj).raycastTarget = false; _fill = ((Component)UiFactory.Fill(UiFactory.Rect((Transform)(object)_bar, "Fill"), 2f)).gameObject.AddComponent<Image>(); _fill.sprite = TexGen.White(); _fill.type = (Type)3; _fill.fillMethod = (FillMethod)0; ((Graphic)_fill).color = new Color(0.45f, 0.95f, 0.5f, 1f); ((Graphic)_fill).raycastTarget = false; ((Component)_root).gameObject.SetActive(false); return true; }, fallback: false); } } internal sealed class LifelineConfig { internal ConfigEntry<float> HoldSeconds { get; } internal ConfigEntry<float> MaxDistance { get; } internal ConfigEntry<int> Health { get; } internal ConfigEntry<int> HealthLoss { get; } internal ConfigEntry<int> MinHealth { get; } internal ConfigEntry<ReviveMode> Mode { get; } internal ConfigEntry<int> RevivesPerPlayer { get; } internal ConfigEntry<int> TeamMin { get; } internal ConfigEntry<float> TeamPerPlayer { get; } internal ConfigEntry<int> TimeLimit { get; } internal ConfigEntry<bool> AllowTombs { get; } internal ConfigEntry<Key> FallbackKey { get; } internal ConfigEntry<bool> DefibEnabled { get; } internal ConfigEntry<int> DefibPrice { get; } internal ConfigEntry<bool> DebugLog { get; } internal LifelineConfig(ConfigFile file) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Expected O, but got Unknown //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown HoldSeconds = file.Bind<float>("Revive", "HoldSeconds", 5f, new ConfigDescription("Host: how long the key must be held.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>())); MaxDistance = file.Bind<float>("Revive", "MaxDistance", 3f, new ConfigDescription("Host: how close you must be to the body or tombstone (m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); Health = file.Bind<int>("Revive", "Health", 35, new ConfigDescription("Host: health after a revive.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); HealthLoss = file.Bind<int>("Revive", "HealthLossPerRevive", 5, new ConfigDescription("Host: each further revive of the same player this round gives this much less health.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); MinHealth = file.Bind<int>("Revive", "MinHealth", 10, new ConfigDescription("Host: never less health than this.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); Mode = file.Bind<ReviveMode>("Rules", "Mode", ReviveMode.PerPlayer, "Host: PerPlayer = each player can be revived RevivesPerPlayer times per round; PerTeam = the crew shares a pool; Unlimited."); RevivesPerPlayer = file.Bind<int>("Rules", "RevivesPerPlayer", 2, new ConfigDescription("Host (PerPlayer).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 99), Array.Empty<object>())); TeamMin = file.Bind<int>("Rules", "TeamRevivesMin", 4, new ConfigDescription("Host (PerTeam): at least this many revives per round...", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 99), Array.Empty<object>())); TeamPerPlayer = file.Bind<float>("Rules", "TeamRevivesPerPlayer", 1.25f, new ConfigDescription("Host (PerTeam): ...or players x this, if more.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); TimeLimit = file.Bind<int>("Rules", "TimeLimitSeconds", 120, new ConfigDescription("Host: seconds after death until a player can no longer be revived (0 = no limit).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3600), Array.Empty<object>())); AllowTombs = file.Bind<bool>("Rules", "AllowTombs", true, "Host: when the body is gone, revive at a tombstone where the player died."); DefibEnabled = file.Bind<bool>("Defibrillator", "Enabled", true, "Host: charges can be bought in the terminal (\"defib buy\"); each revives once beyond the revive limit."); DefibPrice = file.Bind<int>("Defibrillator", "Price", 150, new ConfigDescription("Host: credits per charge.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000), Array.Empty<object>())); FallbackKey = file.Bind<Key>("Input", "KeyWithoutInputUtils", (Key)32, "The revive key when InputUtils is not installed (with InputUtils: rebind it in its keybind menu)."); DebugLog = file.Bind<bool>("Debug", "VerboseLogging", false, "Log every revive request and acknowledgement."); } internal ReviveRules BuildRules() { ReviveRules reviveRules = new ReviveRules(); reviveRules.HoldSeconds = HoldSeconds.Value; reviveRules.MaxDistance = MaxDistance.Value; reviveRules.Health = Health.Value; reviveRules.HealthLossPerRevive = HealthLoss.Value; reviveRules.MinHealth = MinHealth.Value; reviveRules.Mode = Mode.Value; reviveRules.RevivesPerPlayer = RevivesPerPlayer.Value; reviveRules.TeamRevivesMin = TeamMin.Value; reviveRules.TeamRevivesPerPlayer = TeamPerPlayer.Value; reviveRules.TimeLimitSeconds = TimeLimit.Value; reviveRules.AllowTombs = AllowTombs.Value; reviveRules.DefibEnabled = DefibEnabled.Value; reviveRules.DefibPrice = DefibPrice.Value; reviveRules.Validate(); return reviveRules; } } internal static class Net { internal const string Identifier = "lifeline.net"; private const int MaxQueue = 512; private static LNetworkMessage<string>? _msg; internal static readonly Queue<KeyValuePair<ulong, byte[]>> ServerInbox = new Queue<KeyValuePair<ulong, byte[]>>(); internal static readonly Queue<byte[]> ClientInbox = new Queue<byte[]>(); internal static bool Ready => _msg != null; internal static void Init() { if (_msg != null) { return; } try { _msg = Connect(); _msg.OnServerReceived += delegate(string text, ulong sender) { Enqueue(text, delegate(byte[] d) { ServerInbox.Enqueue(new KeyValuePair<ulong, byte[]>(sender, d)); }, ServerInbox.Count); }; _msg.OnClientReceived += delegate(string text) { Enqueue(text, delegate(byte[] d) { ClientInbox.Enqueue(d); }, ClientInbox.Count); }; Log.Info("Lifeline: LethalNetworkAPI message registered (lifeline.net)"); } catch (Exception ex) { _msg = null; Log.Error("Lifeline: LethalNetworkAPI registration failed, revives are off: " + ex); } } [MethodImpl(MethodImplOptions.NoInlining)] private static LNetworkMessage<string> Connect() { return LNetworkMessage<string>.Connect("lifeline.net", (Action<string, ulong>)null, (Action<string>)null, (Action<string, ulong>)null); } private static void Enqueue(string text, Action<byte[]> add, int count) { try { if (count < 512 && WireText.TryDecode(text, out byte[] packet)) { add(packet); } } catch (Exception ex) { Log.ErrorOnce("Lifeline.Net.Receive", "Lifeline: receive failed: " + ex); } } internal static bool IsConnected() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsListening && singleton.IsConnectedClient) { return !singleton.ShutdownInProgress; } return false; } internal static bool IsHost() { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } internal static ulong[] AllClients() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { return Array.Empty<ulong>(); } return new List<ulong>(singleton.ConnectedClientsIds).ToArray(); } internal static void ToServer(Msg m) { if (_msg == null || !IsConnected()) { return; } try { _msg.SendServer(WireText.Encode(Wire.Encode(m))); } catch (Exception ex) { Log.WarnOnce("Lifeline.Net.SendServer", "Lifeline: send to host failed: " + ex.Message); } } internal static void ToClients(byte[] packet, ulong[] targets) { if (_msg == null || targets.Length == 0 || !IsConnected() || !IsHost()) { return; } try { _msg.SendClients(WireText.Encode(packet), targets); } catch (Exception ex) { Log.WarnOnce("Lifeline.Net.SendClients", "Lifeline: send to clients failed: " + ex.Message); } } } [BepInPlugin("dev.thatumi.Lifeline", "Lifeline", "0.2.0")] [BepInDependency("LethalNetworkAPI", "3.4.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private const string LnapiGuid = "LethalNetworkAPI"; private static readonly string[] OtherReviveMods = new string[4] { "UltimateRevive", "ReviveCompany", "BetterRevive", "RevivePlayers" }; private void Awake() { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) LogBepInEx.Init(((BaseUnityPlugin)this).Logger); foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { string[] otherReviveMods = OtherReviveMods; int num = 0; while (num < otherReviveMods.Length) { string value = otherReviveMods[num]; if (pluginInfo.Key.IndexOf(value, StringComparison.OrdinalIgnoreCase) < 0) { BepInPlugin metadata = pluginInfo.Value.Metadata; if ((((metadata != null) ? metadata.Name : null) ?? "").IndexOf(value, StringComparison.OrdinalIgnoreCase) < 0) { num++; continue; } } Log.Error("Lifeline: another revive mod is installed (" + pluginInfo.Key + "). Two revive mods on the same bodies desync revives, so Lifeline is OFF. Remove one of them."); return; } } LifelineConfig cfg; try { cfg = new LifelineConfig(((BaseUnityPlugin)this).Config); } catch (Exception ex) { Log.Error("Lifeline config failed, plugin disabled: " + ex); return; } try { ReviveInput.Init(cfg); } catch (Exception ex2) { Log.Error("Lifeline input setup failed (no revive key): " + ex2); } Net.Init(); Session.Init(cfg); try { Harmony val = new Harmony("dev.thatumi.Lifeline"); val.PatchAll(typeof(GamePatches)); val.PatchAll(typeof(TerminalPatches)); } catch (Exception ex3) { Log.Error("Lifeline: patching failed, revives are off: " + ex3); return; } Runner.Ensure(); Log.Info("Lifeline 0.2.0 loaded"); } } internal sealed class Runner : MonoBehaviour { private static Runner? _instance; private static readonly Action TickAction = Session.Tick; internal static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("LifelineRunner"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; _instance = val.AddComponent<Runner>(); } } private void Update() { if (ReflectionGuard.IsEnabled("Lifeline.Tick")) { ReflectionGuard.Run("Lifeline.Tick", TickAction); } } } internal static class ReviveApplier { private static FieldInfo? _boxes; private static FieldInfo? _boxesAdded; private static FieldInfo? _yOffset; private static bool _looked; internal static bool Apply(ReviveOrder o) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) StartOfRound sor = StartOfRound.Instance; if ((Object)(object)sor == (Object)null || sor.allPlayerScripts == null || o.Slot >= sor.allPlayerScripts.Length) { return false; } PlayerControllerB p = sor.allPlayerScripts[o.Slot]; if ((Object)(object)p == (Object)null) { return false; } if (!p.isPlayerDead) { return true; } Vector3 pos = new Vector3(o.Position.X, o.Position.Y, o.Position.Z); bool num = (Object)(object)p == (Object)(object)GameNetworkManager.Instance?.localPlayerController; Step("Body", delegate { RemoveBody(p, sor); }); Step("Tomb", delegate { Tombs.Remove(o.Slot); }); Step("State", delegate { ResetState(p, sor, o); }); Step("Place", delegate { //IL_0007: Unknown result type (might be due to invalid IL or missing references) p.TeleportPlayer(pos, false, 0f, false, true); p.setPositionOfDeadPlayer = false; p.DisablePlayerModel(sor.allPlayerObjects[o.Slot], true, true); }); Step("Counts", delegate { sor.livingPlayers = Math.Min(sor.livingPlayers + 1, sor.connectedPlayersAmount + 1); sor.allPlayersDead = false; }); if (num) { Step("Owner", delegate { OwnerView(p, sor, o); }); } Step("SpectateBoxes", delegate { RemoveSpectateBox(p); }); Step("Voice", delegate { p.voiceMuffledByEnemy = false; if ((Object)(object)SoundManager.Instance != (Object)null) { SoundManager.Instance.playerVoicePitchTargets[o.Slot] = 1f; SoundManager.Instance.SetPlayerPitch(1f, (int)o.Slot); } sor.UpdatePlayerVoiceEffects(); }); Log.Info("Lifeline: " + p.playerUsername + " revived (" + o.Health + " HP, " + (o.Inside ? "inside" : (o.InShip ? "in the ship" : "outside")) + ")"); return !p.isPlayerDead; } private static void Step(string what, Action body) { try { body(); } catch (Exception ex) { Log.ErrorOnce("Lifeline.Apply." + what, "Lifeline: revive step '" + what + "' failed (the rest still runs): " + ex); } } private static void RemoveBody(PlayerControllerB p, StartOfRound sor) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_0070: Unknown result type (might be due to invalid IL or missing references) DeadBodyInfo deadBody = p.deadBody; if ((Object)(object)deadBody == (Object)null) { return; } GrabbableObject grabBodyObject = deadBody.grabBodyObject; if ((Object)(object)grabBodyObject != (Object)null) { if (grabBodyObject.isHeld && (Object)(object)grabBodyObject.playerHeldBy != (Object)null) { grabBodyObject.playerHeldBy.DropAllHeldItems(true, false, false, false, default(Vector3), default(Vector3), default(Vector3), default(Vector3), default(Vector3)); } if (((NetworkBehaviour)sor).IsServer && (Object)(object)((NetworkBehaviour)grabBodyObject).NetworkObject != (Object)null && ((NetworkBehaviour)grabBodyObject).NetworkObject.IsSpawned) { ((NetworkBehaviour)grabBodyObject).NetworkObject.Despawn(true); } } Object.Destroy((Object)(object)((Component)deadBody).gameObject); p.deadBody = null; } private static void ResetState(PlayerControllerB p, StartOfRound sor, ReviveOrder o) { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) p.ResetPlayerBloodObjects(true); p.isClimbingLadder = false; p.clampLooking = false; p.inVehicleAnimation = false; p.overridePoisonValue = false; p.disableMoveInput = false; p.ResetZAndXRotation(); ((Collider)p.thisController).enabled = true; p.hasBeenCriticallyInjured = false; p.disableLookInput = false; p.disableInteract = false; ((Behaviour)p.nightVisionRadar).enabled = false; p.isPlayerDead = false; p.enemyWaitingForBodyRagdoll = null; p.isPlayerControlled = true; p.isInsideFactory = o.Inside; p.isInElevator = o.InShip; p.isInHangarShipRoom = o.InShip; p.parentedToElevatorLastFrame = false; p.overrideGameOverSpectatePivot = null; ((Behaviour)p.helmetLight).enabled = false; p.Crouch(false); p.criticallyInjured = false; if ((Object)(object)p.playerBodyAnimator != (Object)null) { p.playerBodyAnimator.SetBool("Limp", false); } p.bleedingHeavily = false; p.activatingItem = false; p.twoHanded = false; p.inShockingMinigame = false; p.inSpecialInteractAnimation = false; p.freeRotationInInteractAnimation = false; p.disableSyncInAnimation = false; p.inAnimationWithEnemy = null; p.holdingWalkieTalkie = false; p.speakingToWalkieTalkie = false; p.isSinking = false; p.isUnderwater = false; p.sinkingValue = 0f; p.statusEffectAudio.Stop(); p.DisableJetpackControlsLocally(); p.health = o.Health; p.mapRadarDotAnimator.SetBool("dead", false); p.externalForceAutoFade = Vector3.zero; p.carryWeight = 1f; } private static void OwnerView(PlayerControllerB p, StartOfRound sor, ReviveOrder o) { HUDManager instance = HUDManager.Instance; p.hasBegunSpectating = false; p.spectatedPlayerScript = null; p.hinderedMultiplier = 1f; p.isMovementHindered = 0; p.sourcesCausingSinking = 0; p.isInGameOverAnimation = 0f; ((Renderer)p.thisPlayerModelArms).enabled = true; if (o.InShip) { p.reverbPreset = sor.shipReverb; } sor.SendChangedWeightEvent(); sor.SetSpectateCameraToGameOverMode(false, p); sor.SwitchCamera(p.gameplayCamera); p.ChangeAudioListenerToObject(((Component)p.gameplayCamera).gameObject); if ((Object)(object)instance != (Object)null) { instance.SetCracksOnVisor(100f); instance.gasHelmetAnimator.SetBool("gasEmitting", false); instance.RemoveSpectateUI(); instance.gameOverAnimator.SetTrigger("revive"); instance.HideHUD(false); instance.SetNearDepthOfFieldEnabled(false); ((Behaviour)instance.audioListenerLowPass).enabled = false; instance.cadaverFilter = 0f; instance.UpdateHealthUI((int)o.Health, false); } } private static void RemoveSpectateBox(PlayerControllerB p) { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) HUDManager instance = HUDManager.Instance; if ((Object)(object)instance == (Object)null) { return; } if (!_looked) { _looked = true; _boxes = typeof(HUDManager).GetField("spectatingPlayerBoxes", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _boxesAdded = typeof(HUDManager).GetField("boxesAdded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _yOffset = typeof(HUDManager).GetField("yOffsetAmount", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (_boxes == null) { Log.Warn("Lifeline: HUDManager.spectatingPlayerBoxes not found; revived players may stay in the spectate list."); } } if (!(_boxes?.GetValue(instance) is IDictionary dictionary)) { return; } Animator val = null; foreach (DictionaryEntry item in dictionary) { if (item.Value == p) { object key = item.Key; val = (Animator)((key is Animator) ? key : null); } } if ((Object)(object)val == (Object)null) { return; } if (((Component)val).gameObject.activeSelf && _boxesAdded != null && _yOffset != null) { int num = (int)_boxesAdded.GetValue(instance); float y = ((RectTransform)((Component)val).transform).anchoredPosition.y; List<RectTransform> list = new List<RectTransform>(); foreach (DictionaryEntry item2 in dictionary) { object key2 = item2.Key; Animator val2 = (Animator)((key2 is Animator) ? key2 : null); if (val2 != null && (Object)(object)val2 != (Object)(object)val && ((Component)val2).gameObject.activeSelf) { list.Add((RectTransform)((Component)val2).transform); } } foreach (RectTransform item3 in list) { if (item3.anchoredPosition.y < y) { item3.anchoredPosition = new Vector2(item3.anchoredPosition.x, item3.anchoredPosition.y + 70f); } } _boxesAdded.SetValue(instance, Math.Max(0, num - 1)); _yOffset.SetValue(instance, (float)_yOffset.GetValue(instance) + 70f); } dictionary.Remove(val); Object.Destroy((Object)(object)((Component)val).gameObject); } } internal static class ReviveInput { internal interface IHold { bool Held { get; } string Label { get; } } private sealed class KeyHold : IHold { private readonly LifelineConfig _cfg; public bool Held { get { //IL_0014: 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) Keyboard current = Keyboard.current; if (current == null || (int)_cfg.FallbackKey.Value == 0) { return false; } return ((ButtonControl)current[_cfg.FallbackKey.Value]).isPressed; } } public string Label => ((object)_cfg.FallbackKey.Value/*cast due to .constrained prefix*/).ToString(); internal KeyHold(LifelineConfig cfg) { _cfg = cfg; } } internal const string InputUtilsGuid = "com.rune580.LethalCompanyInputUtils"; private static IHold? _hold; internal static bool Held { get { if (_hold != null) { return _hold.Held; } return false; } } internal static string Label => _hold?.Label ?? "R"; internal static void Init(LifelineConfig cfg) { //IL_0064: 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) if (Chainloader.PluginInfos.ContainsKey("com.rune580.LethalCompanyInputUtils")) { _hold = ReflectionGuard.Run("Lifeline.Input.InputUtils", InputUtilsBridge.Create, null); if (_hold != null) { Log.Info("Lifeline: revive key registered with InputUtils (default R / D-pad up, hold)"); return; } } _hold = new KeyHold(cfg); Log.Info("Lifeline: InputUtils not found, revive key from the config (" + ((object)cfg.FallbackKey.Value/*cast due to .constrained prefix*/).ToString() + ")"); } } internal static class InputUtilsBridge { private sealed class ActionHold : ReviveInput.IHold { private readonly LifelineActions _a; public bool Held { get { if (_a.Revive != null) { return _a.Revive.IsPressed(); } return false; } } public string Label { get { try { InputAction revive = _a.Revive; string text = ((revive != null) ? InputActionRebindingExtensions.GetBindingDisplayString(revive, 0, (DisplayStringOptions)4) : null); return string.IsNullOrEmpty(text) ? "R" : text; } catch (Exception) { return "R"; } } } internal ActionHold(LifelineActions a) { _a = a; } } internal static ReviveInput.IHold Create() { return new ActionHold(new LifelineActions()); } } internal sealed class LifelineActions : LcInputActions { [InputAction("<Keyboard>/r", Name = "Revive (hold)", GamepadPath = "<Gamepad>/dpad/up")] public InputAction Revive { get; set; } } internal static class Session { private const float TombBelowY = -80f; private static LifelineConfig _cfg = null; private static ReviveHost? _host; private static readonly ReviveClient Client = new ReviveClient(); private static readonly HashSet<ulong> Known = new HashSet<ulong>(); private static readonly Dictionary<int, Vector3> DeathPos = new Dictionary<int, Vector3>(); private static readonly Dictionary<int, bool> InsideAtDeath = new Dictionary<int, bool>(); private static readonly List<Send> Sends = new List<Send>(); private static bool _active; private static bool _hostAnswered; private static float _helloAt; private static int _hellos; private static int _charges; private static int _target = -1; private static float _progress; private static float _cooldownUntil; internal static long NowMs => (long)(Time.realtimeSinceStartupAsDouble * 1000.0); internal static void Init(LifelineConfig cfg) { _cfg = cfg; } internal static void Tick() { if (!Net.Ready) { return; } if (!Net.IsConnected() || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance?.localPlayerController == (Object)null) { if (_active) { Stop(); } return; } if (!_active) { Start(); } long now = NowMs; if (_host != null) { int num = 0; while (Net.ServerInbox.Count > 0 && num++ < 128) { KeyValuePair<ulong, byte[]> item = Net.ServerInbox.Dequeue(); ReflectionGuard.Run("Lifeline.Host", delegate { HostReceive(item.Key, item.Value, now); }); } Sends.Clear(); _host.Update(now, ToArray(Known), (int slot) => AliveHere(slot), Sends); foreach (Send send in Sends) { Net.ToClients(send.Data, send.Targets); } } int num2 = 0; while (Net.ClientInbox.Count > 0 && num2++ < 128) { byte[] data = Net.ClientInbox.Dequeue(); ReflectionGuard.Run("Lifeline.Client", delegate { ClientReceive(data, now); }); } if (!_hostAnswered && _hellos < 3 && Time.realtimeSinceStartup >= _helloAt) { _hellos++; _helloAt = Time.realtimeSinceStartup + 10f; Net.ToServer(new HelloMsg()); if (_hellos == 3) { Log.Info("Lifeline: no answer from the host yet; if the host does not run Lifeline, revives are off in this lobby."); } } ReflectionGuard.Run("Lifeline.Tombs", UpdateTombs); ReflectionGuard.Run("Lifeline.Interact", Interact); } internal static void BeforeDeath(int slot) { PlayerControllerB val = PlayerAt(slot); if ((Object)(object)val != (Object)null) { InsideAtDeath[slot] = val.isInsideFactory; } } internal unsafe static void OnDeath(int slot) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0078: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = PlayerAt(slot); if ((Object)(object)val == (Object)null) { return; } Vector3 position = ((Component)val).transform.position; DeathPos[slot] = position; Client.OnDeath(slot, NowMs); if (slot == _target) { ResetHold(); } if (_host != null) { InsideAtDeath.TryGetValue(slot, out var value); _host.OnDeath(slot, new DeathRecord { AtMs = NowMs, Position = V(position), Inside = (value || position.y < -80f), InShip = val.isInHangarShipRoom }); if (_cfg.DebugLog.Value) { string[] obj = new string[5] { "Lifeline: player ", slot.ToString(), " died at ", null, null }; Vector3 val2 = position; obj[3] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(); obj[4] = (value ? " (inside)" : ""); Log.Info(string.Concat(obj)); } } } internal static void OnRoundOver() { Tombs.Clear(); DeathPos.Clear(); InsideAtDeath.Clear(); Client.Reset(); ResetHold(); if (_host != null) { _host.SetRules(_cfg.BuildRules()); _host.BeginRound(PlayerCount()); Net.ToClients(Wire.Encode(new RulesMsg { Rules = _host.Rules }), Net.AllClients()); } } internal static string DefibCommand(bool buy) { ReviveRules rules = Client.Rules; if (!_hostAnswered) { return "DEFIBRILLATOR\nThe host does not run Lifeline, so there are no revives in this lobby."; } if (!rules.DefibEnabled) { return "DEFIBRILLATOR\nDefibrillators are off in this lobby (host config)."; } if (buy) { Net.ToServer(new BuyMsg()); return "DEFIBRILLATOR\nOrdering one charge for " + rules.DefibPrice + " credits.\nThe host confirms it in a moment."; } return "DEFIBRILLATOR\nCharges: " + _charges + "\nPrice: " + rules.DefibPrice + " credits each\n\nA charge revives a crewmate once beyond the revive limit (it is used automatically).\nCharges last until they are used.\n\nType \"defib buy\" to order one."; } private static void Start() { _active = true; _hostAnswered = false; _helloAt = 0f; _hellos = 0; _charges = 0; Known.Clear(); Client.Reset(); Net.ServerInbox.Clear(); Net.ClientInbox.Clear(); if (Net.IsHost()) { _host = new ReviveHost(_cfg.BuildRules()) { Trace = delegate(string s) { Log.Warn("Lifeline: " + s); } }; _host.BeginRound(PlayerCount()); } } private static void Stop() { _active = false; _host = null; Tombs.Clear(); DeathPos.Clear(); Hud.Hide(); ResetHold(); } private static void HostReceive(ulong sender, byte[] data, long now) { byte version; Msg msg = Wire.TryDecode(data, out version); if (msg == null) { if (version != 0 && version != 2) { Log.WarnOnce("Lifeline.Version." + sender, "Lifeline: a player runs another Lifeline version (protocol " + version + "); everyone needs the same one."); } } else { if (!Wire.IsClientToHost(msg.Kind)) { return; } Known.Add(sender); if (!(msg is HelloMsg)) { if (!(msg is BuyMsg)) { if (!(msg is AckMsg ackMsg)) { if (msg is RequestMsg requestMsg) { HostRequest(sender, requestMsg.Slot, now); } return; } _host.OnAck(sender, ackMsg.Seq, ackMsg.StillDead, now); if (_cfg.DebugLog.Value) { Log.Info("Lifeline: ack from " + sender + " for revive " + ackMsg.Seq + (ackMsg.StillDead ? " (still dead there: resending)" : "")); } } else { HostBuy(sender); } } else { Net.ToClients(Wire.Encode(new RulesMsg { Rules = _host.Rules }), new ulong[1] { sender }); Net.ToClients(Wire.Encode(new ChargesMsg { Count = (byte)Mathf.Min(255, _host.Charges) }), new ulong[1] { sender }); } } } private static void HostRequest(ulong sender, int target, long now) { //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: 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) PlayerControllerB val = PlayerOfClient(sender); PlayerControllerB val2 = PlayerAt(target); Refusal refusal = Refusal.Unknown; Vec3? at = null; if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { Vector3? val3 = BodyPosition(val2); if (!val3.HasValue && _host.Rules.AllowTombs && _host.TryDeath(target, out var d)) { at = d.Position; } else if (val3.HasValue) { at = V(val3.Value); } refusal = _host.Check(target, val2.isPlayerDead, !val.isPlayerDead && val.isPlayerControlled, V(((Component)val).transform.position), at, now); } if (refusal != Refusal.None || !at.HasValue) { Net.ToClients(Wire.Encode(new RefusedMsg { Slot = (byte)target, Reason = refusal }), new ulong[1] { sender }); if (_cfg.DebugLog.Value) { Log.Info("Lifeline: revive of " + target + " refused: " + refusal); } return; } bool isInsideFactory = val.isInsideFactory; bool isInHangarShipRoom = val.isInHangarShipRoom; Vector3 navMeshPosition = default(Vector3); ((Vector3)(ref navMeshPosition))..ctor(at.Value.X, at.Value.Y, at.Value.Z); if (!isInHangarShipRoom && (Object)(object)RoundManager.Instance != (Object)null) { navMeshPosition = RoundManager.Instance.GetNavMeshPosition(navMeshPosition, default(NavMeshHit), 2.5f, -1); } int charges = _host.Charges; ReviveOrder reviveOrder = _host.Commit(target, V(navMeshPosition), isInsideFactory, isInHangarShipRoom, ToArray(Known), now); Net.ToClients(ReviveHost.Order(reviveOrder), Net.AllClients()); if (_host.Charges != charges) { Net.ToClients(Wire.Encode(new ChargesMsg { Count = (byte)Mathf.Min(255, _host.Charges) }), Net.AllClients()); Log.Info("Lifeline: a defibrillator charge was used (" + _host.Charges + " left)"); } Log.Info("Lifeline: " + val.playerUsername + " revives " + val2.playerUsername + " (order " + reviveOrder.Seq + ")"); } private static void HostBuy(ulong sender) { ReviveRules rules = _host.Rules; PlayerControllerB val = PlayerOfClient(sender); if (!rules.DefibEnabled) { Net.ToClients(Wire.Encode(new RefusedMsg { Slot = byte.MaxValue, Reason = Refusal.DefibOff }), new ulong[1] { sender }); return; } Terminal val2 = Object.FindObjectOfType<Terminal>(); if ((Object)(object)val2 == (Object)null || val2.groupCredits < rules.DefibPrice) { Net.ToClients(Wire.Encode(new RefusedMsg { Slot = byte.MaxValue, Reason = Refusal.NotEnoughCredits }), new ulong[1] { sender }); return; } val2.groupCredits -= rules.DefibPrice; val2.SyncGroupCreditsClientRpc(val2.groupCredits, val2.numberOfItemsInDropship); _host.AddCharge(); Net.ToClients(Wire.Encode(new ChargesMsg { Count = (byte)Mathf.Min(255, _host.Charges), Bought = (byte)(((Object)(object)val == (Object)null) ? 255u : val.playerClientId) }), Net.AllClients()); Log.Info("Lifeline: " + (val?.playerUsername ?? "someone") + " bought a defibrillator charge (" + _host.Charges + " now)"); } private static void ClientReceive(byte[] data, long now) { byte version; Msg msg = Wire.TryDecode(data, out version); if (!(msg is RulesMsg rulesMsg)) { if (!(msg is ApplyMsg applyMsg)) { if (msg is StateMsg state) { foreach (ReviveOrder item in Client.Reconcile(state, (int slot) => !AliveHere(slot))) { ApplyAndAck(item, now, reconcile: true); } return; } if (!(msg is RefusedMsg refusedMsg)) { if (msg is ChargesMsg chargesMsg) { int charges = _charges; _charges = chargesMsg.Count; if (chargesMsg.Bought != byte.MaxValue && (Object)(object)PlayerAt(chargesMsg.Bought) != (Object)null) { Hud.Toast(PlayerAt(chargesMsg.Bought).playerUsername + " bought a defibrillator charge (" + chargesMsg.Count + " now)", 3f); } else if (chargesMsg.Count < charges) { Hud.Toast("Defibrillator used (" + chargesMsg.Count + " left)", 3f); } } } else { Hud.Toast(Refusals.Text(refusedMsg.Reason), 3f); } } else { ApplyAndAck(applyMsg.Order, now); } } else { Client.Rules = rulesMsg.Rules; _hostAnswered = true; } } private static void ApplyAndAck(ReviveOrder o, long now, bool reconcile = false) { bool deadHere = !AliveHere(o.Slot); if (Client.ShouldApply(o, deadHere, now)) { if (reconcile) { Log.Info("Lifeline: player " + o.Slot + " is alive on the host but dead here: applying revive " + o.Seq + " again"); } ReviveApplier.Apply(o); } Net.ToServer(new AckMsg { Seq = o.Seq, Slot = o.Slot, StillDead = !AliveHere(o.Slot) }); } private static void UpdateTombs() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; for (int i = 0; i < instance.allPlayerScripts.Length; i++) { PlayerControllerB val = instance.allPlayerScripts[i]; if ((Object)(object)val != (Object)null && val.isPlayerDead && !val.disconnectedMidGame && Client.Rules.AllowTombs && _hostAnswered && !BodyPosition(val).HasValue && DeathPos.ContainsKey(i)) { Tombs.Show(i, DeathPos[i]); } else { Tombs.Remove(i); } } } private static void Interact() { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null || localPlayerController.isPlayerDead || !localPlayerController.isPlayerControlled || !_hostAnswered || localPlayerController.inTerminalMenu || localPlayerController.isTypingChat || ((Object)(object)localPlayerController.quickMenuManager != (Object)null && localPlayerController.quickMenuManager.isMenuOpen)) { ResetHold(); Hud.Prompt(null, 0f); return; } ReviveRules rules = Client.Rules; Transform transform = ((Component)localPlayerController.gameplayCamera).transform; int num = -1; float num2 = float.MaxValue; StartOfRound instance = StartOfRound.Instance; for (int i = 0; i < instance.allPlayerScripts.Length; i++) { PlayerControllerB val = instance.allPlayerScripts[i]; if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)localPlayerController || !val.isPlayerDead || val.disconnectedMidGame) { continue; } Vector3? val2 = BodyPosition(val); if (!val2.HasValue && rules.AllowTombs && Tombs.TryGet(i, out var pos)) { val2 = pos + Vector3.up * 0.5f; } if (!val2.HasValue) { continue; } float num3 = Vector3.Distance(((Component)localPlayerController).transform.position, val2.Value); if (!(num3 > rules.MaxDistance)) { Vector3 val3 = val2.Value - transform.position; Vector3 normalized = ((Vector3)(ref val3)).normalized; if (!(Vector3.Dot(transform.forward, normalized) < 0.25f) && num3 < num2) { num2 = num3; num = i; } } } if (num != _target) { _target = num; _progress = 0f; } if (num < 0) { Hud.Prompt(null, 0f); return; } string playerUsername = instance.allPlayerScripts[num].playerUsername; if (Time.realtimeSinceStartup < _cooldownUntil) { Hud.Prompt("Reviving " + playerUsername + "...", 1f); return; } if (ReviveInput.Held) { _progress += Time.deltaTime / Mathf.Max(0.1f, rules.HoldSeconds); } else { _progress = 0f; } if (_progress >= 1f) { Net.ToServer(new RequestMsg { Slot = (byte)num }); _cooldownUntil = Time.realtimeSinceStartup + 1.5f; _progress = 0f; if (_cfg.DebugLog.Value) { Log.Info("Lifeline: revive request for player " + num); } } Hud.Prompt("Hold [" + ReviveInput.Label + "] to revive " + playerUsername, _progress); } private static void ResetHold() { _target = -1; _progress = 0f; } internal static Vector3? BodyPosition(PlayerControllerB p) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) DeadBodyInfo deadBody = p.deadBody; if ((Object)(object)deadBody == (Object)null || !((Component)deadBody).gameObject.activeInHierarchy) { return null; } if ((Object)(object)deadBody.grabBodyObject != (Object)null) { return ((Component)deadBody.grabBodyObject).transform.position; } if (deadBody.bodyParts != null && deadBody.bodyParts.Length != 0 && (Object)(object)deadBody.bodyParts[0] != (Object)null) { return deadBody.bodyParts[0].position; } return ((Component)deadBody).transform.position; } private static bool AliveHere(int slot) { PlayerControllerB val = PlayerAt(slot); if ((Object)(object)val != (Object)null) { return !val.isPlayerDead; } return false; } private static PlayerControllerB? PlayerAt(int slot) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null || slot < 0 || slot >= instance.allPlayerScripts.Length) { return null; } return instance.allPlayerScripts[slot]; } private static PlayerControllerB? PlayerOfClient(ulong clientId) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null) { return null; } PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val != (Object)null && val.actualClientId == clientId && (val.isPlayerControlled || val.isPlayerDead)) { return val; } } return null; } private static int PlayerCount() { StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null)) { return instance.connectedPlayersAmount + 1; } return 1; } private static Vec3 V(Vector3 v) { //IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references) return new Vec3(v.x, v.y, v.z); } private static ulong[] ToArray(HashSet<ulong> set) { ulong[] array = new ulong[set.Count]; set.CopyTo(array); return array; } } internal static class Tombs { private static readonly Dictionary<int, GameObject> Placed = new Dictionary<int, GameObject>(); private static Material? _material; internal static bool TryGet(int slot, out Vector3 pos) { //IL_0001: 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_002d: Unknown result type (might be due to invalid IL or missing references) pos = default(Vector3); if (!Placed.TryGetValue(slot, out GameObject value) || (Object)(object)value == (Object)null) { return false; } pos = value.transform.position; return true; } internal static void Show(int slot, Vector3 deathPos) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_007e: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!Placed.TryGetValue(slot, out GameObject value) || !((Object)(object)value != (Object)null)) { Vector3 position = deathPos; StartOfRound instance = StartOfRound.Instance; int num = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); RaycastHit val = default(RaycastHit); if (Physics.Raycast(deathPos + Vector3.up * 1.5f, Vector3.down, ref val, 30f, num, (QueryTriggerInteraction)1)) { position = ((RaycastHit)(ref val)).point; } GameObject val2 = new GameObject("LifelineTomb" + slot); val2.transform.position = position; Part(val2, new Vector3(0f, 0.45f, 0f), new Vector3(0.55f, 0.9f, 0.14f)); Part(val2, new Vector3(0f, 0.04f, 0f), new Vector3(0.75f, 0.08f, 0.3f)); Placed[slot] = val2; } } internal static void Remove(int slot) { if (Placed.TryGetValue(slot, out GameObject value)) { Placed.Remove(slot); if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } } internal static void Clear() { foreach (GameObject value in Placed.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } Placed.Clear(); } private static void Part(GameObject root, Vector3 local, Vector3 scale) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); Object.Destroy((Object)(object)val.GetComponent<Collider>()); val.transform.SetParent(root.transform, false); val.transform.localPosition = local; val.transform.localScale = scale; Material val2 = Material(); if ((Object)(object)val2 != (Object)null) { val.GetComponent<Renderer>().sharedMaterial = val2; } } private static Material? Material() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_material != (Object)null) { return _material; } Shader val = Shader.Find("HDRP/Lit"); if ((Object)(object)val == (Object)null) { return null; } _material = new Material(val); _material.SetColor("_BaseColor", new Color(0.42f, 0.42f, 0.45f, 1f)); return _material; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "dev.thatumi.Lifeline"; public const string PLUGIN_NAME = "Lifeline"; public const string PLUGIN_VERSION = "0.2.0"; } } namespace Lifeline.Core { public enum Kind : byte { Hello = 1, Request = 2, Ack = 3, Buy = 4, Rules = 20, Apply = 21, State = 22, Refused = 23, Charges = 24 } public abstract class Msg { public abstract Kind Kind { get; } internal abstract void Write(PacketWriter w); internal abstract void Read(PacketReader r); } public sealed class HelloMsg : Msg { public override Kind Kind => Kind.Hello; internal override void Write(PacketWriter w) { } internal override void Read(PacketReader r) { } } public sealed class RequestMsg : Msg { public byte Slot; public override Kind Kind => Kind.Request; internal override void Write(PacketWriter w) { w.Byte(Slot); } internal override void Read(PacketReader r) { Slot = r.Byte(); } } public sealed class AckMsg : Msg { public ushort Seq; public byte Slot; public bool StillDead; public override Kind Kind => Kind.Ack; internal override void Write(PacketWriter w) { w.USho