using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ClassLibrary4")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ClassLibrary4")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("43afb890-208d-4528-aedf-46e3838ce5a8")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] [BepInPlugin("com.user.goi.ghostchaser", "Ghost Chaser Pro", "1.8.0")] public class GhostChaser : BaseUnityPlugin { [Serializable] public class FrameData { public List parts = new List(); } [Serializable] public class PartData { public string name; public Vector3 wPos; public Quaternion wRot; public List children = new List(); } [Serializable] private class RunWrapper { public List frames; } [CompilerGenerated] private sealed class d__26 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public bool recording; public GhostChaser <>4__this; private Joint2D[] <>s__1; private int <>s__2; private Joint2D 5__3; private MonoBehaviour[] <>s__4; private int <>s__5; private MonoBehaviour 5__6; private string 5__7; private Animator[] <>s__8; private int <>s__9; private Animator 5__10; private Rigidbody2D[] <>s__11; private int <>s__12; private Rigidbody2D 5__13; private Transform[] <>s__14; private int <>s__15; private Transform 5__16; private string 5__17; private string 5__18; private Renderer[] <>s__19; private int <>s__20; private Renderer 5__21; private Material[] <>s__22; private int <>s__23; private Material 5__24; private Color 5__25; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = null; 5__3 = null; <>s__4 = null; 5__6 = null; 5__7 = null; <>s__8 = null; 5__10 = null; <>s__11 = null; 5__13 = null; <>s__14 = null; 5__16 = null; 5__17 = null; 5__18 = null; <>s__19 = null; 5__21 = null; <>s__22 = null; 5__24 = null; <>1__state = -2; } private bool MoveNext() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this.startTimer = 6.5f; <>2__current = (object)new WaitForSeconds(6.5f); <>1__state = 1; return true; case 1: <>1__state = -1; if (recording) { <>4__this.currentRun.Clear(); <>4__this.isRecording = true; <>4__this.isPlaying = false; } else { <>4__this.isPlaying = true; <>4__this.isRecording = false; <>4__this.playbackIndex = 0; } if ((Object)(object)<>4__this.player != (Object)null) { <>4__this.ghost = Object.Instantiate(<>4__this.player); ((Object)<>4__this.ghost).name = "GhostVisualClone"; <>4__this.ghostPartCache.Clear(); <>s__1 = <>4__this.ghost.GetComponentsInChildren(true); for (<>s__2 = 0; <>s__2 < <>s__1.Length; <>s__2++) { 5__3 = <>s__1[<>s__2]; Object.Destroy((Object)(object)5__3); 5__3 = null; } <>s__1 = null; <>s__4 = <>4__this.ghost.GetComponentsInChildren(true); for (<>s__5 = 0; <>s__5 < <>s__4.Length; <>s__5++) { 5__6 = <>s__4[<>s__5]; if (!((Object)(object)5__6 == (Object)(object)<>4__this)) { 5__7 = ((object)5__6).GetType().Name; if (5__7.Contains("IK") || 5__7.Contains("Control") || 5__7.Contains("Animator") || 5__7.Contains("PlayerControl") || 5__7.Contains("Saviour") || 5__7.Contains("PlayerSounds") || 5__7.Contains("Sounds")) { Object.DestroyImmediate((Object)(object)5__6); } 5__7 = null; 5__6 = null; } } <>s__4 = null; <>s__8 = <>4__this.ghost.GetComponentsInChildren(true); for (<>s__9 = 0; <>s__9 < <>s__8.Length; <>s__9++) { 5__10 = <>s__8[<>s__9]; Object.DestroyImmediate((Object)(object)5__10); 5__10 = null; } <>s__8 = null; <>s__11 = <>4__this.ghost.GetComponentsInChildren(); for (<>s__12 = 0; <>s__12 < <>s__11.Length; <>s__12++) { 5__13 = <>s__11[<>s__12]; 5__13.isKinematic = true; 5__13.simulated = false; 5__13 = null; } <>s__11 = null; <>s__14 = <>4__this.ghost.GetComponentsInChildren(true); for (<>s__15 = 0; <>s__15 < <>s__14.Length; <>s__15++) { 5__16 = <>s__14[<>s__15]; 5__17 = (((Object)(object)5__16.parent != (Object)null) ? ((Object)5__16.parent).name : ""); if (5__17 == "GhostVisualClone" || 5__17 == "Player(Clone)") { 5__17 = "Player"; } 5__18 = (((Object)(object)5__16.parent != (Object)null) ? (5__17 + "_" + ((Object)5__16).name + "_" + 5__16.GetSiblingIndex()) : ((Object)5__16).name); if ((Object)(object)5__16 == (Object)(object)<>4__this.ghost.transform) { 5__18 = "Player"; } if (!<>4__this.ghostPartCache.ContainsKey(5__18)) { <>4__this.ghostPartCache.Add(5__18, 5__16); } 5__17 = null; 5__18 = null; 5__16 = null; } <>s__14 = null; <>s__19 = <>4__this.ghost.GetComponentsInChildren(); for (<>s__20 = 0; <>s__20 < <>s__19.Length; <>s__20++) { 5__21 = <>s__19[<>s__20]; if (recording) { 5__21.enabled = false; } else { <>s__22 = 5__21.materials; for (<>s__23 = 0; <>s__23 < <>s__22.Length; <>s__23++) { 5__24 = <>s__22[<>s__23]; if (5__24.HasProperty("_Color")) { 5__25 = 5__24.color; 5__25.a = 0.4f; 5__24.color = 5__25; } 5__24 = null; } <>s__22 = null; } 5__21 = null; } <>s__19 = null; } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__23 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public GhostChaser <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__23(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)<>4__this.player == (Object)null) { <>4__this.player = GameObject.Find("Player"); <>2__current = null; <>1__state = 1; return true; } <>4__this.showMenu = true; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private GameObject player; private GameObject ghost; private bool isRecording = false; private bool isPlaying = false; private bool showMenu = false; private float startTimer = -1f; private Dictionary ghostPartCache = new Dictionary(); private bool showSaveSelection = false; private Vector2 scrollPosition = Vector2.zero; private string selectedFilePath = ""; private string renameString = ""; private List currentRun = new List(); private int playbackIndex = 0; private string SavesFolder => Path.Combine(Application.persistentDataPath, "ghost_saves"); private string DefaultSavePath => Path.Combine(SavesFolder, "ghost_run.json"); private void Awake() { SceneManager.sceneLoaded += OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { Cleanup(); ((MonoBehaviour)this).StartCoroutine(WaitAndShowMenu()); } private void Cleanup() { if ((Object)(object)ghost != (Object)null) { Object.Destroy((Object)(object)ghost); } ghostPartCache.Clear(); isRecording = false; isPlaying = false; showSaveSelection = false; selectedFilePath = ""; startTimer = -1f; Time.timeScale = 1f; if (!Directory.Exists(SavesFolder)) { Directory.CreateDirectory(SavesFolder); } } [IteratorStateMachine(typeof(d__23))] private IEnumerator WaitAndShowMenu() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__23(0) { <>4__this = this }; } private void Update() { if (showMenu) { Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else { if ((Object)(object)player == (Object)null) { return; } if (startTimer > 0f) { startTimer -= Time.deltaTime; return; } if (isRecording) { RecordFrame(); } if (isPlaying && (Object)(object)ghost != (Object)null && currentRun.Count > 0) { ApplyFrame(playbackIndex); playbackIndex = (playbackIndex + 1) % currentRun.Count; } } } private void OnGUI() { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_054a: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) if (showMenu) { Time.timeScale = 0f; if (!showSaveSelection) { Rect val = default(Rect); ((Rect)(ref val))..ctor((float)(Screen.width / 2 - 120), (float)(Screen.height / 2 - 80), 240f, 160f); GUI.Box(val, "GHOST MENU"); if (GUI.Button(new Rect(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 30f, 200f, 35f), "RECORD NEW RUN")) { Cursor.visible = false; Cursor.lockState = (CursorLockMode)1; showMenu = false; Time.timeScale = 1f; ((MonoBehaviour)this).StartCoroutine(InitiateSequence(recording: true)); } string[] files = Directory.GetFiles(SavesFolder, "*.json"); if ((files.Length != 0 || File.Exists(DefaultSavePath)) && GUI.Button(new Rect(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 75f, 200f, 35f), "PLAY LAST RUN")) { showSaveSelection = true; } } else { Rect val2 = default(Rect); ((Rect)(ref val2))..ctor((float)(Screen.width / 2 - 250), (float)(Screen.height / 2 - 180), 500f, 360f); GUI.Box(val2, "SELECT OR RENAME RUN TRACKS"); string[] files2 = Directory.GetFiles(SavesFolder, "*.json"); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref val2)).x + 15f, ((Rect)(ref val2)).y + 30f, 470f, 200f); Rect val4 = default(Rect); ((Rect)(ref val4))..ctor(0f, 0f, 450f, (float)Mathf.Max(200, files2.Length * 32)); scrollPosition = GUI.BeginScrollView(val3, scrollPosition, val4); for (int i = 0; i < files2.Length; i++) { string text = files2[i]; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); string text2 = ((selectedFilePath == text) ? ("> " + fileNameWithoutExtension + " <") : fileNameWithoutExtension); if (GUI.Button(new Rect(5f, (float)(i * 32), 440f, 28f), text2)) { selectedFilePath = text; renameString = fileNameWithoutExtension; } } GUI.EndScrollView(); if (!string.IsNullOrEmpty(selectedFilePath) && File.Exists(selectedFilePath)) { GUI.Label(new Rect(((Rect)(ref val2)).x + 20f, ((Rect)(ref val2)).y + 245f, 100f, 25f), "Rename to:"); renameString = GUI.TextField(new Rect(((Rect)(ref val2)).x + 110f, ((Rect)(ref val2)).y + 245f, 240f, 25f), renameString); if (GUI.Button(new Rect(((Rect)(ref val2)).x + 360f, ((Rect)(ref val2)).y + 245f, 120f, 25f), "Apply Name") && !string.IsNullOrEmpty(renameString.Trim())) { string text3 = Path.Combine(SavesFolder, renameString.Trim() + ".json"); if (!File.Exists(text3)) { File.Move(selectedFilePath, text3); selectedFilePath = text3; } } if (GUI.Button(new Rect(((Rect)(ref val2)).x + 20f, ((Rect)(ref val2)).y + 290f, 210f, 40f), "LOAD SELECTED RUN")) { Cursor.visible = false; Cursor.lockState = (CursorLockMode)1; LoadRunDirect(selectedFilePath); showSaveSelection = false; showMenu = false; Time.timeScale = 1f; ((MonoBehaviour)this).StartCoroutine(InitiateSequence(recording: false)); } } else { GUI.Label(new Rect(((Rect)(ref val2)).x + 20f, ((Rect)(ref val2)).y + 250f, 460f, 30f), "Select a file from the list above to proceed...", GUI.skin.box); } if (GUI.Button(new Rect(((Rect)(ref val2)).x + 260f, ((Rect)(ref val2)).y + 290f, 220f, 40f), "BACK TO MENU")) { showSaveSelection = false; selectedFilePath = ""; } } } if (!showMenu) { if (startTimer > 0f) { GUI.Label(new Rect(20f, 20f, 200f, 30f), $"GHOST STARTING: {startTimer:F1}s"); } if (isRecording && GUI.Button(new Rect((float)(Screen.width - 140), (float)(Screen.height - 45), 130f, 35f), "SAVE RUN")) { SaveRun(); } } } [IteratorStateMachine(typeof(d__26))] private IEnumerator InitiateSequence(bool recording) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__26(0) { <>4__this = this, recording = recording }; } private void RecordFrame() { if (!((Object)(object)player == (Object)null)) { FrameData frameData = new FrameData(); frameData.parts.Add(RecordTransformRecursive(player.transform)); currentRun.Add(frameData); } } private PartData RecordTransformRecursive(Transform current) { //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_0020: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown PartData partData = new PartData { name = ((Object)current).name, wPos = current.position, wRot = current.rotation }; foreach (Transform item in current) { Transform current2 = item; partData.children.Add(RecordTransformRecursive(current2)); } return partData; } private void ApplyFrame(int index) { if (!((Object)(object)ghost == (Object)null) && index < currentRun.Count) { FrameData frameData = currentRun[index]; if (frameData.parts.Count > 0) { ApplyTransformRecursive(ghost.transform, frameData.parts[0]); } } } private void ApplyTransformRecursive(Transform current, PartData data) { //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) if ((Object)(object)current == (Object)null || data == null) { return; } current.position = data.wPos; current.rotation = data.wRot; for (int i = 0; i < data.children.Count; i++) { if (i < current.childCount) { ApplyTransformRecursive(current.GetChild(i), data.children[i]); } } } private void SaveRun() { if (currentRun.Count != 0) { string text = $"run_{DateTime.Now:yyyyMMdd_HHmmss}.json"; string path = Path.Combine(SavesFolder, text); File.WriteAllText(path, JsonUtility.ToJson((object)new RunWrapper { frames = currentRun })); Debug.Log((object)("Ghost Run Saved to: " + text)); } } private void LoadRunDirect(string fullPath) { if (File.Exists(fullPath)) { RunWrapper runWrapper = JsonUtility.FromJson(File.ReadAllText(fullPath)); if (runWrapper != null && runWrapper.frames != null) { currentRun = runWrapper.frames; } } } }