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 PSOFOSDeath v3.6.1
BepInEx/plugins/PSOFOSDeath/PSOFOSDeath.dll
Decompiled 9 months agousing 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 BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("PSOFOSDeath")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PSOFOSDeath")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e1c6268f-b8b6-49c2-b44e-6adbecdd155f")] [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.yourname.psofosdeath", "PSOFOS Death Overlay", "3.6.1")] public class PSOFOSDeath : BaseUnityPlugin { public class DeathHeartbeat : MonoBehaviour { [CompilerGenerated] private sealed class <Tick>d__3 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DeathHeartbeat <>4__this; private WaitForSeconds <wait>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Tick>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <wait>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown int num = <>1__state; DeathHeartbeat deathHeartbeat = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <wait>5__2 = new WaitForSeconds(0.25f); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } bool flag = false; try { flag = deathHeartbeat.DetectDeadByReflection(); } catch { } if (flag && !deathHeartbeat._lastDead) { deathHeartbeat._overlay?.PlayOneShotIfReady(); } deathHeartbeat._lastDead = flag; <>2__current = <wait>5__2; <>1__state = 2; return true; } 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 DeathOverlay _overlay; private bool _lastDead; public void Init(DeathOverlay overlay) { _overlay = overlay; ((MonoBehaviour)this).StartCoroutine(Tick()); } [IteratorStateMachine(typeof(<Tick>d__3))] private IEnumerator Tick() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Tick>d__3(0) { <>4__this = this }; } private bool DetectDeadByReflection() { MonoBehaviour[] array = Object.FindObjectsOfType<MonoBehaviour>(); foreach (MonoBehaviour val in array) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); string name = type.Name; if (name.IndexOf("PlayerAvatar", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("StatsManager", StringComparison.OrdinalIgnoreCase) < 0) { continue; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { string text = fieldInfo.Name.ToLowerInvariant(); if ((text == "isdead" || text == "dead") && fieldInfo.FieldType == typeof(bool)) { try { if ((bool)fieldInfo.GetValue(val)) { return true; } } catch { } } if (text.Contains("health") && (fieldInfo.FieldType == typeof(int) || fieldInfo.FieldType == typeof(float))) { try { if (Convert.ToSingle(fieldInfo.GetValue(val)) <= 0f) { return true; } } catch { } } if (!(text == "isdisabled") || !(fieldInfo.FieldType == typeof(bool))) { continue; } try { if ((bool)fieldInfo.GetValue(val)) { return true; } } catch { } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (!propertyInfo.CanRead) { continue; } string text2 = propertyInfo.Name.ToLowerInvariant(); if ((!(text2 == "isdead") && !(text2 == "dead")) || !(propertyInfo.PropertyType == typeof(bool))) { continue; } try { if ((bool)propertyInfo.GetValue(val, null)) { return true; } } catch { } } } return false; } } public class DeathOverlay : MonoBehaviour { [CompilerGenerated] private sealed class <EnsureListenerAfterDelay>d__7 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DeathOverlay <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnsureListenerAfterDelay>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; DeathOverlay deathOverlay = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: { <>1__state = -1; bool flag = false; AudioListener[] array = Object.FindObjectsOfType<AudioListener>(); foreach (AudioListener val in array) { if ((Object)(object)val != (Object)null && ((Behaviour)val).enabled) { flag = true; break; } } if (!flag) { deathOverlay._busGO.AddComponent<AudioListener>(); ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[PSOFOS] No enabled AudioListener detected after delay; attached a temporary fallback listener."); } } 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 <LoadClips>d__8 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DeathOverlay <>4__this; private string[] <names>5__2; private int <i>5__3; private string <name>5__4; private UnityWebRequest <req>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadClips>d__8(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <names>5__2 = null; <name>5__4 = null; <req>5__5 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; DeathOverlay deathOverlay = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -3; if (<req>5__5.isNetworkError || <req>5__5.isHttpError) { Debug.LogWarning((object)("[PSOFOS] Failed to load " + <name>5__4 + ": " + <req>5__5.error)); } else { AudioClip content = DownloadHandlerAudioClip.GetContent(<req>5__5); if (!((Object)(object)content == (Object)null)) { ((Object)content).name = <name>5__4; deathOverlay._clips.Add(content); Debug.Log((object)("[PSOFOS] Loaded " + <name>5__4)); <>m__Finally1(); <req>5__5 = null; <name>5__4 = null; goto IL_018d; } Debug.LogWarning((object)("[PSOFOS] Loaded null clip for " + <name>5__4)); } <>m__Finally1(); goto IL_018d; } <>1__state = -1; <names>5__2 = new string[3] { "PSOFOS01.ogg", "PSOFOS02.ogg", "PSOFOS03.ogg" }; <i>5__3 = 0; goto IL_019f; IL_019f: if (<i>5__3 < <names>5__2.Length) { <name>5__4 = <names>5__2[<i>5__3]; string text = Path.Combine(deathOverlay._pluginDir, <name>5__4); if (File.Exists(text)) { string absoluteUri = new Uri(text).AbsoluteUri; <req>5__5 = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)14); <>1__state = -3; <>2__current = <req>5__5.SendWebRequest(); <>1__state = 1; return true; } goto IL_018d; } if (deathOverlay._clips.Count == 0) { Debug.LogWarning((object)("[PSOFOS] No OGGs found. Expected next to DLL at: " + deathOverlay._pluginDir)); } return false; IL_018d: <i>5__3++; goto IL_019f; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<req>5__5 != null) { ((IDisposable)<req>5__5).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly List<AudioClip> _clips = new List<AudioClip>(); private AudioSource _bus; private GameObject _busGO; private string _pluginDir; private float _cooldownUntil; public void Init() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); _pluginDir = (string.IsNullOrEmpty(directoryName) ? Path.Combine(Paths.PluginPath, "PSOFOSDeath") : directoryName); try { Directory.CreateDirectory(_pluginDir); } catch { } EnsureBus(); ((MonoBehaviour)this).StartCoroutine(LoadClips()); } private void EnsureBus() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (!((Object)(object)_bus != (Object)null)) { _busGO = new GameObject("PSOFOS_AudioBus"); ((Object)_busGO).hideFlags = (HideFlags)52; Object.DontDestroyOnLoad((Object)(object)_busGO); _bus = _busGO.AddComponent<AudioSource>(); _bus.playOnAwake = false; _bus.spatialBlend = 0f; _bus.priority = 0; _bus.volume = 1.35f; _bus.bypassReverbZones = true; _bus.bypassEffects = true; _bus.bypassListenerEffects = true; _bus.dopplerLevel = 0f; _bus.reverbZoneMix = 0f; ((MonoBehaviour)this).StartCoroutine(EnsureListenerAfterDelay()); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[PSOFOS] Created PSOFOS audio bus."); } } } [IteratorStateMachine(typeof(<EnsureListenerAfterDelay>d__7))] private IEnumerator EnsureListenerAfterDelay() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnsureListenerAfterDelay>d__7(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<LoadClips>d__8))] private IEnumerator LoadClips() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadClips>d__8(0) { <>4__this = this }; } public void PlayOneShotIfReady() { if (Time.unscaledTime < _cooldownUntil || _clips.Count == 0) { return; } EnsureBus(); if ((Object)(object)_bus == (Object)null) { return; } AudioClip val = _clips[Random.Range(0, _clips.Count)]; try { if (((Behaviour)_bus).isActiveAndEnabled && ((Component)_bus).gameObject.activeInHierarchy) { _bus.PlayOneShot(val, 1f); _cooldownUntil = Time.unscaledTime + 1f; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[PSOFOS] Death event -> played '" + ((Object)val).name + "'.")); } } } catch (Exception ex) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)("[PSOFOS] OneShot play failed: " + ex)); } } } } internal static ManualLogSource Log; private Harmony _harmony; private static DeathOverlay _overlay; private void Awake() { //IL_0010: 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: Expected O, but got Unknown //IL_001b: 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) //IL_0040: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; GameObject val = new GameObject("PSOFOS_DeathOverlay"); Object.DontDestroyOnLoad((Object)val); _overlay = val.AddComponent<DeathOverlay>(); _overlay.Init(); _harmony = new Harmony("com.yourname.psofosdeath.harmony"); Type type = AccessTools.TypeByName("PlayerAvatar"); TryPatchPostfix(type, "PlayerDeath", "OnDeathPostfix"); TryPatchPostfix(type, "PlayerDeathRPC", "OnDeathPostfix"); TryPatchPostfix(type, "PlayerDeathDone", "OnDeathPostfix"); val.AddComponent<DeathHeartbeat>().Init(_overlay); Log.LogInfo((object)"[PSOFOS] v3.6.1 initialized (3.2 hooks + edge-detected watcher)"); } private void TryPatchPostfix(Type type, string method, string handlerName) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown if (type == null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[PSOFOS] Type not found for method: " + method)); } return; } MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null); if (methodInfo == null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)("[PSOFOS] Method not found: " + ((type != null) ? type.Name : "null") + "." + method + "()")); } return; } HarmonyMethod val = new HarmonyMethod(typeof(PSOFOSDeath).GetMethod(handlerName, BindingFlags.Static | BindingFlags.NonPublic)); _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ManualLogSource log3 = Log; if (log3 != null) { log3.LogInfo((object)("[PSOFOS] Patched " + type.Name + "." + method + "()")); } } private static void OnDeathPostfix() { try { _overlay?.PlayOneShotIfReady(); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[PSOFOS] DeathPostfix error: " + ex)); } } } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } }