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 Odins Long Drop v0.1.0
plugins/OdinsLongDrop.dll
Decompiled 2 weeks agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("OdinsLongDrop")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+1ab61fc24b8bfec3aefe11a9768c25d4d04073ad")] [assembly: AssemblyProduct("OdinsLongDrop")] [assembly: AssemblyTitle("OdinsLongDrop")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OdinsLongDrop { internal static class HudText { private sealed class Scale : MonoBehaviour { private const float ReferenceWidth = 1920f; private const float ReferenceHeight = 1080f; private static readonly FieldRef<float> GameGuiScale = TryFindGuiScale(); internal CanvasScaler Scaler; private float _logged = -1f; private void Update() { if (!((Object)(object)Scaler == (Object)null)) { float num = ((GameGuiScale != null) ? GameGuiScale.Invoke() : 1f); if (num <= 0f) { num = 1f; } float num2 = Mathf.Min((float)Screen.width / 1920f, (float)Screen.height / 1080f) * num * Plugin.TextScale.Value; if (Mathf.Abs(Scaler.scaleFactor - num2) > 0.0001f) { Scaler.scaleFactor = num2; } if (Plugin.DebugLog.Value && Mathf.Abs(_logged - num2) > 0.0001f) { _logged = num2; Plugin.Log.LogInfo((object)$"Text scale {num2:0.###}: screen {Screen.width}x{Screen.height}, game GUI scale {num:0.##}, TextScale {Plugin.TextScale.Value:0.##}."); } } } private static FieldRef<float> TryFindGuiScale() { FieldInfo fieldInfo = AccessTools.Field(typeof(GuiScaler), "m_largeGuiScale"); if (fieldInfo == null || fieldInfo.FieldType != typeof(float) || !fieldInfo.IsStatic) { Plugin.Log.LogWarning((object)"Couldn't find the game's GUI scale; text follows the screen size only."); return null; } return AccessTools.StaticFieldRefAccess<float>(fieldInfo); } } private static Canvas _canvas; public static TMP_Text Create(string name, Transform owner) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) TMP_Text val = (((Object)(object)MessageHud.instance != (Object)null) ? MessageHud.instance.m_messageCenterText : null); if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null || !EnsureCanvas(owner)) { return null; } GameObject val2 = new GameObject(name, new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(((Component)_canvas).transform, false); TextMeshProUGUI obj = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).font = val.font; ((TMP_Text)obj).fontSharedMaterial = val.fontSharedMaterial; ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj).textWrappingMode = (TextWrappingModes)1; ((Graphic)obj).raycastTarget = false; ((TMP_Text)obj).outlineWidth = 0.15f; ((TMP_Text)obj).outlineColor = new Color32((byte)0, (byte)0, (byte)0, (byte)200); RectTransform val3 = (RectTransform)val2.transform; val3.pivot = new Vector2(0.5f, 0.5f); val3.anchoredPosition = Vector2.zero; return (TMP_Text)(object)obj; } private static bool EnsureCanvas(Transform owner) { //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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_canvas != (Object)null) { return true; } GameObject val = new GameObject("OdinsLongDrop_Canvas"); val.transform.SetParent(owner, false); _canvas = val.AddComponent<Canvas>(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 5000; CanvasScaler val2 = val.AddComponent<CanvasScaler>(); val2.uiScaleMode = (ScaleMode)0; val.AddComponent<Scale>().Scaler = val2; Plugin.Log.LogInfo((object)"On-screen text layer created."); return true; } } internal sealed class LongDrop : MonoBehaviour { private enum Kind { None, Ledge, Falling } private const float ScanInterval = 0.1f; private const float SafeDrop = 4f; private const float FullDamageAfter = 16f; private const float FullDamage = 100f; private const float ProbeHeight = 0.6f; private const float Step = 0.5f; private const int SlopeWindow = 2; private const float LandingRun = 1.5f; private const float MaxLipDistance = 3f; private const float MinReach = 6f; private const float MaxReach = 60f; private const float AimRange = 200f; private const int ProfilePoints = 24; private const float LedgeLogEvery = 1f; private const float MaxRay = 1000f; private const float Linger = 0.35f; private const float NewDropAfter = 2f; private const float RemarkCooldown = 10f; private const float FeetPerMetre = 3.28084f; private static readonly FieldRef<Character, float> MaxAirAltitude = AccessTools.FieldRefAccess<Character, float>("m_maxAirAltitude"); private static readonly string[] LedgeLines = new string[4] { "{0}. About {1} damage. You have {2}. Odin would take the stairs.", "{0} down, {2} health to pay with. The ground charges {1}.", "{0}. About {1} damage, and you have {2}. Odin is only mentioning it.", "That's {0}. The landing costs about {1}. You have {2}. Odin has done the sums." }; private static readonly string[] FallingLines = new string[3] { "{0}. About {1} damage. You have {2}. Too late for the stairs.", "About {1} damage on the way, {2} health to meet it. Odin will tell the skalds it was deliberate.", "{0}, {1} damage, {2} health. Odin did mention it. Well, he's mentioning it now." }; private Readout _readout; private OdinLine _line; private int _groundMask; private int _waterMask; private int _blockMask; private float _nextScan; private Kind _showing; private bool _showingFatal; private float _lastSeen = -100f; private bool _warned; private float _nextRemarkAt; private string _lastRemark; private float _nextLedgeLog; private readonly StringBuilder _why = new StringBuilder(); internal static LongDrop Instance { get; private set; } private void Awake() { Instance = this; _readout = ((Component)this).gameObject.AddComponent<Readout>(); _line = ((Component)this).gameObject.AddComponent<OdinLine>(); _groundMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "terrain", "blocker", "vehicle" }); _waterMask = LayerMask.GetMask(new string[1] { "Water" }); _blockMask = LayerMask.GetMask(new string[5] { "piece", "Default", "static_solid", "Default_small", "terrain" }); } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (Time.time < _nextScan) { return; } _nextScan = Time.time + 0.1f; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !Plugin.Enabled.Value || Busy(localPlayer)) { Clear(now: true); return; } float drop; Kind kind = Look(localPlayer, out drop); if (kind == Kind.None) { if (_showing == Kind.Ledge && !((Character)localPlayer).IsOnGround() && !((Character)localPlayer).IsSwimming()) { _lastSeen = Time.time; } Clear(now: false); } else { Show(localPlayer, kind, drop); } } private Kind Look(Player player, out float drop) { //IL_001f: 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) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) drop = 0f; if (((Character)player).IsAttached() || ((Character)player).IsSwimming()) { return Kind.None; } Vector3 position = ((Component)player).transform.position; float value = Plugin.MinDrop.Value; if (!((Character)player).IsOnGround()) { if (!Plugin.ShowWhileFalling.Value) { return Kind.None; } float num = MaxAirAltitude.Invoke((Character)(object)player); if (num - position.y < value || !SurfaceBelow(position + Vector3.up * 0.1f, out var height)) { return Kind.None; } drop = num - height; return Kind.Falling; } bool flag = Plugin.DebugLog.Value && Time.time >= _nextLedgeLog; _why.Length = 0; Kind result = Ledge(player, position, value, flag, out drop); if (flag && _why.Length > 0) { _nextLedgeLog = Time.time + 1f; Plugin.Log.LogInfo((object)_why.ToString()); } return result; } private Kind Ledge(Player player, Vector3 feet, float min, bool log, out float drop) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0072: 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) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018c: 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_0196: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: 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) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) drop = 0f; Vector3 lookDir = ((Character)player).GetLookDir(); float num = Mathf.Asin(Mathf.Clamp(0f - lookDir.y, -1f, 1f)) * 57.29578f; float value = Plugin.LookDownAngle.Value; if (num < value) { return Kind.None; } if (!Plugin.ShowAtLedge.Value) { if (log) { _why.Append("Ledge check: looking down, but ShowAtLedge is off in the config."); } return Kind.None; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(lookDir.x, 0f, lookDir.z); if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { ((Vector3)(ref val))..ctor(((Component)player).transform.forward.x, 0f, ((Component)player).transform.forward.z); } if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { return Kind.None; } ((Vector3)(ref val)).Normalize(); float value2 = Plugin.SlopeAngle.Value; float num2 = Mathf.Tan(value2 * ((float)Math.PI / 180f)) * 0.5f * 2f; string aim; float num3 = Reach(feet, out aim); int num4 = Mathf.CeilToInt(num3 / 0.5f); if (log) { _why.Append($"Ledge check, looking {num:0} deg down (needs {value:0}), slope limit {value2:0} deg, standing on {Describe(((Character)player).GetLastGroundCollider())} at y {feet.y:0.0}, {aim}:"); } float[] array = new float[num4 + 1]; array[0] = feet.y; Vector3 val2 = feet + Vector3.up * 0.6f; Vector3 val3 = val2; int num5 = -1; int num6 = -1; int num7 = 0; string text = null; RaycastHit val5 = default(RaycastHit); for (int i = 1; i <= num4; i++) { float num8 = (float)i * 0.5f; Vector3 val4 = val2 + val * num8; if (Physics.Linecast(val3, val4, ref val5, _blockMask, (QueryTriggerInteraction)1)) { if (num5 < 0) { if (log) { _why.Append($" {num8:0.0} m: blocked by {Describe(((RaycastHit)(ref val5)).collider)} before any edge. No ledge."); } return Kind.None; } num6 = i - 1; text = $"runs into {Describe(((RaycastHit)(ref val5)).collider)} at {num8:0.0} m"; break; } val3 = val4; if (!SurfaceBelow(val4, out var height, out var what)) { height = array[i - 1]; } array[i] = height; int num9 = Mathf.Max(0, i - 2); bool flag = array[num9] - height > num2 * (float)(i - num9) / 2f; if (num5 < 0) { if (flag) { num5 = i; } else if (num8 > 3f) { if (log) { _why.Append($" standable ground for {3f:0} m: not at an edge.{Profile(array, feet.y, i)}"); } return Kind.None; } } else if (flag) { num7 = 0; } else { num7++; if ((float)num7 * 0.5f >= 1.5f) { num6 = i - num7 + 1; text = $"levels out at {(float)num6 * 0.5f:0.0} m on {what}"; break; } } } if (num5 < 0) { if (log) { _why.Append($" no edge within {num3:0} m.{Profile(array, feet.y, num4)}"); } return Kind.None; } if (num6 < 0) { num6 = num4; text = $"still going at {(float)num4 * 0.5f:0.0} m, so counted to the end of the line"; } float num10 = array[Mathf.Max(0, num5 - 1)]; drop = num10 - array[num6]; if (log) { _why.Append($" edge at {(float)(num5 - 1) * 0.5f:0.0} m (y {num10:0.0}), {text}, y {array[num6]:0.0}: {drop:0.0} m down"); } if (drop < min) { if (log) { _why.Append($", under MinDrop {min:0.#} m. No readout.{Profile(array, feet.y, num6)}"); } drop = 0f; return Kind.None; } if (log) { _why.Append(". A ledge." + Profile(array, feet.y, num6)); } return Kind.Ledge; } private float Reach(Vector3 feet, out string aim) { //IL_0024: 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_0053: 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_0059: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) GameCamera instance = GameCamera.instance; if ((Object)(object)instance == (Object)null) { aim = "no camera"; return 6f; } Transform transform = ((Component)instance).transform; RaycastHit val = default(RaycastHit); if (!Physics.Raycast(transform.position, transform.forward, ref val, 200f, _groundMask, (QueryTriggerInteraction)1)) { aim = "crosshair on nothing"; return 60f; } Vector3 val2 = ((RaycastHit)(ref val)).point - feet; val2.y = 0f; float magnitude = ((Vector3)(ref val2)).magnitude; aim = $"crosshair on {Describe(((RaycastHit)(ref val)).collider)} {magnitude:0.0} m out, {feet.y - ((RaycastHit)(ref val)).point.y:0.0} m down"; return Mathf.Clamp(magnitude + 0.5f, 6f, 60f); } private static string Profile(float[] heights, float feet, int last) { if (!Plugin.DebugLog.Value || last < 1) { return ""; } StringBuilder stringBuilder = new StringBuilder(" Profile (m out: m down):"); int num = Mathf.Max(1, Mathf.CeilToInt((float)last / 24f)); for (int i = num; i <= last; i += num) { stringBuilder.Append($" {(float)i * 0.5f:0.#}: {feet - heights[i]:0.0}"); } return stringBuilder.ToString(); } private static string Describe(Collider collider) { if ((Object)(object)collider == (Object)null) { return "nothing known"; } string text = LayerMask.LayerToName(((Component)collider).gameObject.layer); Transform root = ((Component)collider).transform.root; if (!((Object)(object)root != (Object)null) || !((Object)(object)root != (Object)(object)((Component)collider).transform)) { return ((Object)collider).name + " (" + text + ")"; } return ((Object)collider).name + " (" + text + ", in " + ((Object)root).name + ")"; } private bool SurfaceBelow(Vector3 from, out float height) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string what; return SurfaceBelow(from, out height, out what); } private bool SurfaceBelow(Vector3 from, out float height, out string what) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) height = float.MinValue; what = null; bool result = false; RaycastHit val = default(RaycastHit); if (Physics.Raycast(from, Vector3.down, ref val, 1000f, _groundMask, (QueryTriggerInteraction)1)) { height = ((RaycastHit)(ref val)).point.y; what = (Plugin.DebugLog.Value ? Describe(((RaycastHit)(ref val)).collider) : null); result = true; } RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(from, Vector3.down, ref val2, 1000f, _waterMask, (QueryTriggerInteraction)2) && ((RaycastHit)(ref val2)).point.y > height) { height = ((RaycastHit)(ref val2)).point.y; what = "water"; result = true; } return result; } private static float Damage(Player player, float drop) { if (drop <= 4f) { return 0f; } float num = Mathf.Clamp01((drop - 4f) / 16f) * 100f; float num2 = num; ((Character)player).GetSEMan().ModifyFallDamage(num, ref num2); if (num2 <= 0f) { return 0f; } num2 *= Game.m_localDamgeTakenRate; if (!(num2 <= 0.1f)) { return num2; } return 0f; } private void Show(Player player, Kind kind, float drop) { float health = ((Character)player).GetHealth(); float num = Damage(player, drop); bool flag = num > 0f && health - num <= 0f && !((Character)player).InGodMode() && !((Character)player).InGhostMode(); int num2 = Mathf.Max(1, Mathf.RoundToInt(num)); int num3 = Mathf.CeilToInt(health); string text = Height(drop, spoken: false); string line = ((num <= 0f) ? (text + " drop, no damage") : ((!flag) ? $"{text} drop, about {num2} damage, {Mathf.Max(1, Mathf.CeilToInt(health - num))} health left" : $"{text} drop, about {num2} damage, you have {num3}")); string damage = ((num <= 0f) ? "no dmg" : $"~{num2} dmg"); _readout.Show(text, damage, line, flag); if (_showing == Kind.None && Time.time - _lastSeen > 2f) { _warned = false; } if (kind != _showing || flag != _showingFatal) { Note(string.Format("{0}: {1:0.0} m, {2:0.0} damage, {3:0.0} health{4}.", kind, drop, num, health, flag ? ", would kill you" : "")); } _showing = kind; _showingFatal = flag; _lastSeen = Time.time; if (flag && !_warned) { _warned = true; Warn(kind, Height(drop, spoken: true), num2, num3); } } private void Clear(bool now) { if (_showing != Kind.None && (now || !(Time.time - _lastSeen < 0.35f))) { _readout.Hide(); _showing = Kind.None; _showingFatal = false; } } private void Warn(Kind kind, string height, int damage, int health) { if (!Plugin.WarnIfFatal.Value) { return; } if (Time.time < _nextRemarkAt) { Note("Would kill you, but Odin spoke a moment ago. He's letting the red do the talking."); return; } string[] array = ((kind == Kind.Falling) ? FallingLines : LedgeLines); string text = null; for (int i = 0; i < 8; i++) { if (text != null && !(text == _lastRemark)) { break; } text = string.Format(array[Random.Range(0, array.Length)], Capitalise(height), damage, health); } _lastRemark = text; _nextRemarkAt = Time.time + 10f; _line.Show(text); Note("Odin warned you: \"" + text + "\""); } private static string Height(float metres, bool spoken) { bool flag = Plugin.Units.Value == "feet"; int num = Mathf.Max(1, Mathf.RoundToInt(flag ? (metres * 3.28084f) : metres)); if (!spoken) { if (!flag) { return $"{num} m"; } return $"{num} ft"; } if (flag) { if (num != 1) { return $"{num} feet"; } return "1 foot"; } if (num != 1) { return $"{num} metres"; } return "1 metre"; } private static string Capitalise(string s) { if (s.Length <= 0) { return s; } return char.ToUpperInvariant(s[0]) + s.Substring(1); } private static bool Busy(Player player) { if (!((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).InCutscene() && !((Character)player).InIntro() && !((Character)player).IsDebugFlying() && !Menu.IsVisible() && !InventoryGui.IsVisible()) { return Minimap.IsOpen(); } return true; } private static void Note(string message) { if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)message); } } } internal class OdinLine : MonoBehaviour { private const float ScreenY = 0.72f; private const float FadeIn = 0.2f; private const float Hold = 3.5f; private const float FadeOut = 0.8f; private const float TextSize = 21f; private static readonly Color Tint = new Color(1f, 0.86f, 0.62f); private TMP_Text _text; private float _elapsed = -1f; public void Show(string line) { if (EnsureText()) { _text.text = line; _elapsed = 0f; SetAlpha(0f); ((Component)_text).gameObject.SetActive(true); } } private void Update() { if (_elapsed < 0f || (Object)(object)_text == (Object)null) { return; } _elapsed += Time.deltaTime; float num = 4.5f; if (_elapsed >= num) { _elapsed = -1f; ((Component)_text).gameObject.SetActive(false); return; } float num2 = Mathf.Min(Mathf.Clamp01(_elapsed / 0.2f), Mathf.Clamp01((num - _elapsed) / 0.8f)); if (!HudVisible()) { num2 = 0f; } SetAlpha(Mathf.SmoothStep(0f, 1f, num2)); } private void SetAlpha(float alpha) { //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_0014: Unknown result type (might be due to invalid IL or missing references) Color tint = Tint; tint.a = alpha; ((Graphic)_text).color = tint; } private bool EnsureText() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0066: 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) if ((Object)(object)_text != (Object)null) { return true; } _text = HudText.Create("OdinsLongDrop_Line", ((Component)this).transform); if ((Object)(object)_text == (Object)null) { return false; } RectTransform val = (RectTransform)_text.transform; val.anchorMin = new Vector2(0.5f, 0.72f); val.anchorMax = new Vector2(0.5f, 0.72f); val.sizeDelta = new Vector2(1400f, 160f); _text.fontSize = 21f; return true; } private static bool HudVisible() { if ((Object)(object)Hud.instance != (Object)null && !Hud.IsUserHidden()) { return Hud.instance.IsVisible(); } return false; } private void OnDestroy() { if ((Object)(object)_text != (Object)null) { Object.Destroy((Object)(object)((Component)_text).gameObject); } } } [BepInPlugin("hevyh2o.valheim.odinslongdrop", "Odin's Long Drop", "0.1.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "hevyh2o.valheim.odinslongdrop"; public const string Name = "Odin's Long Drop"; public const string Version = "0.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> ShowAtLedge; internal static ConfigEntry<bool> ShowWhileFalling; internal static ConfigEntry<float> MinDrop; internal static ConfigEntry<bool> WarnIfFatal; internal static ConfigEntry<string> Units; internal static ConfigEntry<string> Style; internal static ConfigEntry<float> TextScale; internal static ConfigEntry<float> SlopeAngle; internal static ConfigEntry<float> LookDownAngle; internal static ConfigEntry<bool> DebugLog; private LongDrop _longDrop; private void Awake() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch."); ShowAtLedge = ((BaseUnityPlugin)this).Config.Bind<bool>("Readout", "ShowAtLedge", true, "Show the readout when you stand at an edge and look down over a drop of at least MinDrop."); SlopeAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Readout", "SlopeAngle", 38f, new ConfigDescription("Ground steeper than this, in degrees, counts as part of a drop, 20 to 80. 38 is the game's own limit: anything steeper and you slide down it instead of standing on it. Higher = only steeper slopes and cliffs count.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 80f), Array.Empty<object>())); LookDownAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Readout", "LookDownAngle", 14f, new ConfigDescription("How far below level, in degrees, you have to look for the ledge readout to check the ground ahead, 5 to 60.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 60f), Array.Empty<object>())); ShowWhileFalling = ((BaseUnityPlugin)this).Config.Bind<bool>("Readout", "ShowWhileFalling", true, "Show the readout once you've been falling for at least MinDrop."); MinDrop = ((BaseUnityPlugin)this).Config.Bind<float>("Readout", "MinDrop", 4f, new ConfigDescription("Smallest drop worth showing, in metres, 1 to 20. The game starts to hurt you above 4; below that the readout just says \"no damage\".", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>())); Units = ((BaseUnityPlugin)this).Config.Bind<string>("Readout", "Units", "metres", new ConfigDescription("Show heights in metres or feet.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "metres", "feet" }), Array.Empty<object>())); Style = ((BaseUnityPlugin)this).Config.Bind<string>("Readout", "Style", "BesideCrosshair", new ConfigDescription("Where the readout goes. BesideCrosshair: two short lines just left of the crosshair, the drop and the damage. BelowCrosshair: one line under the crosshair with the drop, the damage and the health you'd have left.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "BesideCrosshair", "BelowCrosshair" }), Array.Empty<object>())); TextScale = ((BaseUnityPlugin)this).Config.Bind<float>("Readout", "TextScale", 1f, new ConfigDescription("Size of the readout and Odin's warning line, 0.5 to 2. 1 = sized to match the game's own HUD, which already follows your screen height and the game's GUI scale setting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>())); WarnIfFatal = ((BaseUnityPlugin)this).Config.Bind<bool>("Messages", "WarnIfFatal", true, "When the landing would kill you, Odin says so in one line, once per drop. Off = the readout still turns red, Odin keeps quiet."); DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "Write each readout Odin starts (drop, damage, health), each warning, the text scale, and, at most once a second while you look down, why a ledge did or didn't count (what each probe hit, its layer and the drop) to the BepInEx log."); _longDrop = ((Component)this).gameObject.AddComponent<LongDrop>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Odin's Long Drop 0.1.0 loaded. Odin has done the sums."); } private void OnDestroy() { if ((Object)(object)_longDrop != (Object)null) { Object.Destroy((Object)(object)_longDrop); } } } internal class Readout : MonoBehaviour { internal const string BesideCrosshair = "BesideCrosshair"; internal const string BelowCrosshair = "BelowCrosshair"; private const float BesideGap = 20f; private const float BesideTextSize = 17f; private const string DamageSize = "80%"; private const float BelowScreenY = 0.4f; private const float BelowTextSize = 16f; private const float FadeIn = 0.15f; private const float FadeOut = 0.4f; private static readonly Color Safe = new Color(0.92f, 0.92f, 0.88f); private static readonly Color Fatal = new Color(1f, 0.32f, 0.26f); private TMP_Text _text; private bool _beside; private bool _laidOut; private bool _wanted; private bool _fatal; private float _alpha; internal static bool Beside => Plugin.Style.Value != "BelowCrosshair"; public void Show(string drop, string damage, string line, bool fatal) { if (EnsureText()) { bool beside = Beside; if (!_laidOut || beside != _beside) { Layout(beside); } string text = (beside ? (drop + "\n<size=80%>" + damage + "</size>") : line); if (_text.text != text) { _text.text = text; } _fatal = fatal; _wanted = true; ((Component)_text).gameObject.SetActive(true); } } public void Hide() { _wanted = false; } private void Update() { //IL_0090: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_text == (Object)null)) { float num = ((_wanted && HudVisible()) ? 1f : 0f); float num2 = ((num > _alpha) ? 6.6666665f : 2.5f); _alpha = Mathf.MoveTowards(_alpha, num, num2 * Time.deltaTime); if (_alpha <= 0f && !_wanted) { ((Component)_text).gameObject.SetActive(false); return; } Color color = (_fatal ? Fatal : Safe); color.a = Mathf.SmoothStep(0f, 1f, _alpha); ((Graphic)_text).color = color; } } private bool EnsureText() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_text != (Object)null) { return true; } _text = HudText.Create("OdinsLongDrop_Readout", ((Component)this).transform); if ((Object)(object)_text == (Object)null) { return false; } ((Graphic)_text).color = new Color(Safe.r, Safe.g, Safe.b, 0f); return true; } private void Layout(bool beside) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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_0030: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)_text.transform; Vector2 val2 = default(Vector2); if (beside) { ((Vector2)(ref val2))..ctor(0.5f, 0.5f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(1f, 0.5f); val.sizeDelta = new Vector2(180f, 60f); val.anchoredPosition = new Vector2(-20f, 0f); _text.alignment = (TextAlignmentOptions)516; _text.textWrappingMode = (TextWrappingModes)0; _text.lineSpacing = -12f; _text.fontSize = 17f; } else { ((Vector2)(ref val2))..ctor(0.5f, 0.4f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(0.5f, 0.5f); val.sizeDelta = new Vector2(700f, 60f); val.anchoredPosition = Vector2.zero; _text.alignment = (TextAlignmentOptions)514; _text.textWrappingMode = (TextWrappingModes)1; _text.lineSpacing = 0f; _text.fontSize = 16f; } _beside = beside; _laidOut = true; } private static bool HudVisible() { if ((Object)(object)Hud.instance != (Object)null && !Hud.IsUserHidden()) { return Hud.instance.IsVisible(); } return false; } private void OnDestroy() { if ((Object)(object)_text != (Object)null) { Object.Destroy((Object)(object)((Component)_text).gameObject); } } } internal static class BuildInfo { public const string Version = "0.1.0"; } }