using System; using System.Collections.Generic; using System.Reflection; using Harmony; using MSCLoader; using UnityEngine; namespace MSCO { /// /// Solange ein Eingabefenster offen ist (F8-Konsole, Chat, Admin-Menü): Spieler bewegt sich nicht, /// Kamera dreht nicht mit, Mauszeiger ist frei. Danach wird genau das wieder eingeschaltet, /// was hier ausgeschaltet wurde. /// public static class InputLock { static readonly string[] ControlScripts = { "CharacterMotor", "FPSInputController", "MouseLook", "SimpleSmoothMouseLook", "SmoothMouseLook", "MouseLook2", "MouseLook3" }; static readonly List disabled = new List(); static bool locked; static bool previousVisible; static CursorLockMode previousLock; static bool patched; public static bool Locked { get { return locked; } } public static void Set(bool on) { if (on) KeepCursorFree(); if (on == locked) return; locked = on; if (on) { PatchCursorActions(); previousVisible = Cursor.visible; previousLock = Cursor.lockState; GameObject player = GameObject.Find("PLAYER"); if (player != null) { foreach (MonoBehaviour mb in player.GetComponentsInChildren()) { if (mb == null || !mb.enabled || Array.IndexOf(ControlScripts, mb.GetType().Name) < 0) continue; mb.enabled = false; disabled.Add(mb); } } KeepCursorFree(); } else { foreach (Behaviour b in disabled) if (b != null) b.enabled = true; disabled.Clear(); PlayMakerGUI.LockCursor = previousLock != CursorLockMode.None; PlayMakerGUI.HideCursor = !previousVisible; Cursor.visible = previousVisible; Cursor.lockState = previousLock; } } /// /// Das Spiel sperrt den Zeiger jeden Frame wieder (PlayMakerGUI.LockCursor + "SetMouseCursor"-Aktionen), /// dadurch springt er in die Mitte. Solange offen: überall freigeben - auch aus OnGUI/LateUpdate aufrufen. /// public static void KeepCursorFree() { if (!locked) return; PlayMakerGUI.LockCursor = false; PlayMakerGUI.HideCursor = false; Cursor.visible = true; Cursor.lockState = CursorLockMode.None; } /// PlayMaker-Aktionen, die den Mauszeiger setzen, überspringen, solange ein Fenster offen ist. static void PatchCursorActions() { if (patched) return; patched = true; try { Type action = null; foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) { action = asm.GetType("HutongGames.PlayMaker.Actions.SetMouseCursor"); if (action != null) break; } if (action == null) return; HarmonyInstance harmony = HarmonyInstance.Create("mbm.msco.inputlock"); var prefix = new HarmonyMethod(typeof(InputLock).GetMethod("SkipWhileLocked", BindingFlags.Static | BindingFlags.NonPublic)); foreach (string name in new[] { "OnEnter", "OnUpdate", "DoSetMouseCursor" }) { MethodInfo m = action.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (m != null && m.DeclaringType == action) harmony.Patch(m, prefix, null); } } catch (Exception e) { ModConsole.Warning("[MSCO] Could not patch cursor actions: " + e.Message); } } static bool SkipWhileLocked() { return !locked; } } }