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 Unstuck v0.2.1
Unstuck.dll
Decompiled 6 days agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace Unstuck; [BepInPlugin("com.burks.unstuck", "Unstuck", "0.2.1")] public class UnstuckPlugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__22_0; internal void <Update>b__22_0(ConsoleEventArgs a) { Begin(a.Context); } } public const string GUID = "com.burks.unstuck"; public const string NAME = "Unstuck"; public const string VERSION = "0.2.1"; public static ManualLogSource Log; public static ConfigEntry<KeyCode> Key; public static ConfigEntry<float> WaitSeconds; public static ConfigEntry<float> CooldownSeconds; public static ConfigEntry<float> MaxDistance; public static ConfigEntry<float> MaxClimb; public static ConfigEntry<float> CalmSeconds; private static readonly FieldRef<Character, Rigidbody> Body = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body"); private static readonly FieldRef<Character, float> MaxAir = AccessTools.FieldRefAccess<Character, float>("m_maxAirAltitude"); private static bool _channel; private static float _lastMax = -1f; private static float _endsAt; private static float _readyAt; private static float _lastHurt = -999f; private static float _lastHealth = -1f; private static float _lastShown; private static Vector3 _startPos; private static bool _cmd; private void Awake() { //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Invalid comparison between Unknown and I4 Log = ((BaseUnityPlugin)this).Logger; Key = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "Key", (KeyCode)0, "Optional hotkey. The console command 'unstuck' always works."); WaitSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "WaitSeconds", 10f, "You must stand still and unharmed this long before you are moved."); CooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "CooldownSeconds", 300f, "Time between uses."); MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "MaxDistance", 10f, "Furthest you can be moved, in metres. The nearest safe spot is always used."); MaxClimb = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "MaxClimb", 2f, "The new spot can be at most this many metres higher than where you are, so it cannot be used to climb."); CalmSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "CalmSeconds", 15f, "Not usable until this long after you were last hurt."); if ((int)SystemInfo.graphicsDeviceType == 4) { ((Behaviour)this).enabled = false; } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Unstuck 0.2.1 loaded."); } } private void Update() { //IL_0060: 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) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { _channel = false; _lastHealth = -1f; return; } if (!_cmd) { _cmd = true; try { object obj = <>c.<>9__22_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs a) { Begin(a.Context); }; <>c.<>9__22_0 = val; obj = (object)val; } new ConsoleCommand("unstuck", "free your character if it is stuck (stand still for a few seconds)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } catch (Exception ex) { Log.LogWarning((object)("Could not add the 'unstuck' command: " + ex.Message)); } } try { MenuButton.Ensure(); } catch (Exception ex2) { if (!MenuButton.Failed) { MenuButton.Failed = true; Log.LogWarning((object)("Could not add the menu button, using a plain one instead: " + ex2.Message)); } } float health = ((Character)localPlayer).GetHealth(); float maxHealth = ((Character)localPlayer).GetMaxHealth(); float num = ((_lastMax > 0f) ? Mathf.Max(0f, _lastMax - maxHealth) : 0f); if (_lastHealth >= 0f && _lastHealth - health > num + 1f) { _lastHurt = Time.time; } _lastHealth = health; _lastMax = maxHealth; try { if ((int)Key.Value != 0 && Input.GetKeyDown(Key.Value) && !Console.IsVisible() && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus())) { Begin(null); } if (_channel) { Channel(localPlayer); } } catch (Exception ex3) { _channel = false; Log.LogWarning((object)("Unstuck failed: " + ex3)); } } private static void Tell(Terminal ctx, string text) { if ((Object)(object)ctx != (Object)null) { ctx.AddString(text); } if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true); } } private static string Blocked(Player me) { if (((Character)me).IsDead() || ((Character)me).IsTeleporting() || ((Character)me).InBed() || me.IsSleeping()) { return "You can't do that right now."; } if (((Character)me).IsAttached()) { return "Stand up or let go first."; } if (((Character)me).InInterior()) { return "Unstuck doesn't work inside dungeons."; } if (Time.time - _lastHurt < Mathf.Max(0f, CalmSeconds.Value)) { return "You were hurt too recently."; } if (me.IsTargeted() || me.IsSensed()) { return "Not while enemies are aware of you."; } return null; } private void OnGUI() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (MenuButton.Failed && !((Object)(object)Player.m_localPlayer == (Object)null) && Menu.IsVisible() && GUI.Button(new Rect((float)Screen.width / 2f - 90f, (float)Screen.height - 90f, 180f, 40f), "Unstuck")) { MenuButton.Click(); } } public static void Begin(Terminal ctx) { //IL_0090: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } if (_channel) { Tell(ctx, "Already freeing you - stand still."); return; } float num = _readyAt - Time.time; if (num > 0f) { Tell(ctx, "Unstuck is ready again in " + Mathf.CeilToInt(num) + " s."); return; } string text = Blocked(localPlayer); if (text != null) { Tell(ctx, text); return; } if (!FindSpot(localPlayer, out var _)) { Tell(ctx, "No safe spot close by."); return; } _channel = true; _startPos = ((Component)localPlayer).transform.position; _endsAt = Time.time + Mathf.Clamp(WaitSeconds.Value, 3f, 120f); _lastShown = 0f; Tell(ctx, "Freeing you in " + Mathf.CeilToInt(_endsAt - Time.time) + " s. Stand still."); } private static void Channel(Player me) { //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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: 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_0193: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) string text = Blocked(me); if (text != null) { _channel = false; Tell(null, "Unstuck cancelled. " + text); return; } Vector3 val = ((Component)me).transform.position - _startPos; if (((Vector3)(ref val)).magnitude > 1.5f) { _channel = false; Tell(null, "Unstuck cancelled - you moved."); return; } float num = _endsAt - Time.time; if (num > 0f) { if (Time.time - _lastShown >= 1f) { _lastShown = Time.time; Tell(null, "Freeing you in " + Mathf.CeilToInt(num) + " s"); } return; } _channel = false; if (!FindSpot(me, out var best)) { Tell(null, "No safe spot close by."); return; } Vector3 position = ((Component)me).transform.position; ((Component)me).transform.position = best; Rigidbody val2 = Body.Invoke((Character)(object)me); if ((Object)(object)val2 != (Object)null) { val2.position = best; val2.velocity = Vector3.zero; } Physics.SyncTransforms(); MaxAir.Invoke((Character)(object)me) = best.y; _readyAt = Time.time + Mathf.Max(0f, CooldownSeconds.Value); Tell(null, "You are free."); ManualLogSource log = Log; string[] obj = new string[5] { "Moved ", null, null, null, null }; val = best - position; obj[1] = ((Vector3)(ref val)).magnitude.ToString("0.0"); obj[2] = " m ("; obj[3] = (best.y - position.y).ToString("0.0"); obj[4] = " m up)."; log.LogInfo((object)string.Concat(obj)); } private static bool FindSpot(Player me, out Vector3 best) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) best = Vector3.zero; if ((Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return false; } Vector3 position = ((Component)me).transform.position; float waterLevel = ZoneSystem.instance.m_waterLevel; float num = Mathf.Clamp(MaxDistance.Value, 3f, 30f); float num2 = Mathf.Clamp(MaxClimb.Value, 0f, 10f); bool flag = PrivateArea.CheckAccess(position, 0f, false, false); float num7 = default(float); Vector3 val2 = default(Vector3); GameObject val3 = default(GameObject); for (float num3 = 2f; num3 <= num + 0.01f; num3 += 1f) { int num4 = Mathf.Max(8, Mathf.RoundToInt(num3 * 4f)); float num5 = Random.Range(0f, (float)Math.PI * 2f); for (int i = 0; i < num4; i++) { float num6 = num5 + (float)i * (float)Math.PI * 2f / (float)num4; Vector3 val = position + new Vector3(Mathf.Cos(num6), 0f, Mathf.Sin(num6)) * num3; if (ZNetScene.instance.IsAreaReady(val) && ZoneSystem.instance.GetSolidHeight(val, ref num7, ref val2, ref val3) && !(num7 < waterLevel - 0.5f) && !(num7 - position.y > num2) && !(position.y - num7 > 30f) && !(val2.y < 0.7f)) { val.y = num7 + 0.3f; if ((!flag || PrivateArea.CheckAccess(val, 0f, false, false)) && !Physics.CheckCapsule(val + Vector3.up * 0.5f, val + Vector3.up * 1.5f, 0.3f, LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" }))) { best = val; return true; } } } } return false; } } public static class MenuButton { public static bool Failed; private static GameObject _button; public static void Ensure() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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 if (!Failed && !((Object)(object)_button != (Object)null) && !((Object)(object)Menu.instance == (Object)null)) { Button settingsButton = Menu.instance.m_settingsButton; if ((Object)(object)settingsButton == (Object)null) { throw new Exception("no Settings button to copy"); } GameObject val = Object.Instantiate<GameObject>(((Component)settingsButton).gameObject, ((Component)settingsButton).transform.parent); ((Object)val).name = "UnstuckButton"; val.transform.SetSiblingIndex(((Component)settingsButton).transform.GetSiblingIndex() + 1); Button component = val.GetComponent<Button>(); component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener(new UnityAction(Click)); TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = "Unstuck"; } _button = val; UnstuckPlugin.Log.LogInfo((object)"Added the Unstuck button to the menu."); } } public static void Click() { try { if ((Object)(object)Menu.instance != (Object)null) { Menu.instance.Hide(); } } catch (Exception) { } UnstuckPlugin.Begin(null); } }