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.Versioning; using System.Threading; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("EepyDeepy")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+030e29ed8d52a55f233ed8cf9e4b25cf3c101f2a")] [assembly: AssemblyProduct("EepyDeepy")] [assembly: AssemblyTitle("EepyDeepy")] [assembly: AssemblyVersion("1.0.0.0")] namespace EepyDeepy; public class SequenceEntry { public int Seconds; public string Message; } public class EepyDeepyConfig { public List Sequence = new List(); } [BepInPlugin("com.byawn.eepydeepy", "EepyDeepy", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class EepyDeepyPlugin : BaseUnityPlugin { public const string PluginGUID = "com.byawn.eepydeepy"; public const string PluginName = "EepyDeepy"; public const string PluginVersion = "1.0.3"; internal static ManualLogSource Log; internal static EepyDeepyPlugin Instance; private Harmony harmony; private EepyDeepyConfig config; private string configPath; private FileSystemWatcher configWatcher; private DateTime lastConfigReload = DateTime.MinValue; private int sequenceIndex; private bool sequenceActive; private readonly HashSet playersInBed = new HashSet(); private AudioSource audioSource; private AudioClip lullaby; internal CustomRPC bedEnterRPC; internal CustomRPC bedExitRPC; private CustomRPC playLullabyRPC; private CustomRPC stopLullabyRPC; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00d2: Expected O, but got Unknown //IL_00e9: 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_00ff: Expected O, but got Unknown //IL_00ff: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_012c: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0159: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Instance = this; harmony = new Harmony("com.byawn.eepydeepy"); harmony.PatchAll(); configPath = Path.Combine(Paths.ConfigPath, "eepydeepy.cfg"); LoadConfig(); StartConfigWatcher(); if (!GUIManager.IsHeadless()) { audioSource = ((Component)this).gameObject.AddComponent(); audioSource.loop = true; audioSource.volume = 0f; string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "lullaby.ogg"); ((MonoBehaviour)this).StartCoroutine(LoadAudio(path)); } bedEnterRPC = NetworkManager.Instance.AddRPC("BedEnter", new CoroutineHandler(RPC_OnBedEnter), new CoroutineHandler(RPC_NoOp)); bedExitRPC = NetworkManager.Instance.AddRPC("BedExit", new CoroutineHandler(RPC_OnBedExit), new CoroutineHandler(RPC_NoOp)); playLullabyRPC = NetworkManager.Instance.AddRPC("PlayLullaby", new CoroutineHandler(RPC_NoOp), new CoroutineHandler(RPC_OnPlayLullaby)); stopLullabyRPC = NetworkManager.Instance.AddRPC("StopLullaby", new CoroutineHandler(RPC_NoOp), new CoroutineHandler(RPC_OnStopLullaby)); Log.LogInfo((object)"EepyDeepy v1.0.3 loaded."); } private IEnumerator RPC_NoOp(long sender, ZPackage package) { yield break; } private IEnumerator RPC_OnBedEnter(long sender, ZPackage package) { Log.LogInfo((object)$"RPC_OnBedEnter received from {sender}."); OnPlayerBedEnter(sender, "RPC"); yield break; } private IEnumerator RPC_OnBedExit(long sender, ZPackage package) { Log.LogInfo((object)$"RPC_OnBedExit received from {sender}."); OnPlayerBedExit(sender); yield break; } private IEnumerator RPC_OnPlayLullaby(long sender, ZPackage package) { Log.LogInfo((object)$"RPC_OnPlayLullaby received. lullaby={(Object)(object)lullaby != (Object)null} audioSource={(Object)(object)audioSource != (Object)null}"); StartMusic(); yield break; } private IEnumerator RPC_OnStopLullaby(long sender, ZPackage package) { Log.LogInfo((object)"RPC_OnStopLullaby received."); ((MonoBehaviour)this).StopAllCoroutines(); ((MonoBehaviour)this).StartCoroutine(FadeOutMusic(3f)); yield break; } private IEnumerator LoadAudio(string path) { if (!File.Exists(path)) { Log.LogWarning((object)("Lullaby not found at " + path + ". No music will play.")); yield break; } UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip("file://" + path, (AudioType)14); try { yield return req.SendWebRequest(); if ((int)req.result != 1) { Log.LogError((object)("Failed to load lullaby: " + req.error)); yield break; } lullaby = DownloadHandlerAudioClip.GetContent(req); Log.LogInfo((object)"Lullaby loaded."); } finally { ((IDisposable)req)?.Dispose(); } } private void StartMusic() { Log.LogInfo((object)$"StartMusic called. lullaby={(Object)(object)lullaby != (Object)null} audioSource={(Object)(object)audioSource != (Object)null}"); if (!((Object)(object)lullaby == (Object)null)) { audioSource.clip = lullaby; audioSource.volume = 0f; audioSource.Play(); Log.LogInfo((object)"Audio playing."); ((MonoBehaviour)this).StartCoroutine(FadeInMusic(3f)); } } private IEnumerator FadeInMusic(float duration) { float t = 0f; while (t < duration) { t += Time.deltaTime; audioSource.volume = Mathf.Clamp01(t / duration); yield return null; } audioSource.volume = 1f; } private IEnumerator FadeOutMusic(float duration) { float startVolume = audioSource.volume; float t = 0f; while (t < duration) { t += Time.deltaTime; audioSource.volume = Mathf.Clamp01(startVolume * (1f - t / duration)); yield return null; } audioSource.Stop(); audioSource.volume = 0f; } private void LoadConfig() { if (!File.Exists(configPath)) { Log.LogError((object)("Config not found at " + configPath + ".")); return; } EepyDeepyConfig eepyDeepyConfig = new EepyDeepyConfig(); string[] array = File.ReadAllLines(configPath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (string.IsNullOrEmpty(text) || text.StartsWith("#")) { continue; } int num = text.IndexOf(' '); if (num >= 0) { string s = text.Substring(0, num).Trim(); string text2 = text.Substring(num + 1).Trim(); if (int.TryParse(s, out var result) && !string.IsNullOrEmpty(text2)) { eepyDeepyConfig.Sequence.Add(new SequenceEntry { Seconds = result, Message = text2 }); } } } config = eepyDeepyConfig; LogConfig(); } private void LogConfig() { Log.LogInfo((object)$"Config loaded: {config.Sequence.Count} sequence entries."); foreach (SequenceEntry item in config.Sequence) { Log.LogInfo((object)$" [{item.Seconds}s] {item.Message}"); } } private void StartConfigWatcher() { configWatcher = new FileSystemWatcher(Paths.ConfigPath, "eepydeepy.cfg"); configWatcher.NotifyFilter = NotifyFilters.LastWrite; configWatcher.Changed += OnConfigChanged; configWatcher.EnableRaisingEvents = true; } private void OnConfigChanged(object sender, FileSystemEventArgs e) { if (!((DateTime.Now - lastConfigReload).TotalSeconds < 1.0)) { lastConfigReload = DateTime.Now; Thread.Sleep(200); Log.LogInfo((object)"Config file changed, reloading..."); LoadConfig(); } } public void OnPlayerBedEnter(long playerId, string trigger) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown if (!playersInBed.Add(playerId)) { return; } ZNet instance = ZNet.instance; string text = ((instance == null) ? null : instance.GetPeer(playerId)?.m_playerName) ?? ""; Log.LogInfo((object)$"Player {text} ({playerId}) triggered EepyDeepy via {trigger}. Players in bed: {playersInBed.Count}"); if (!sequenceActive) { sequenceActive = true; sequenceIndex = 0; Log.LogInfo((object)("Starting EepyDeepy sequence, triggered by " + text + " via " + trigger + ".")); ((MonoBehaviour)this).StartCoroutine(RunSequence()); playLullabyRPC.SendPackage(ZRoutedRpc.Everybody, new ZPackage()); if (!GUIManager.IsHeadless()) { StartMusic(); } } } public void OnPlayerBedExit(long playerId) { if (playersInBed.Remove(playerId)) { ZNet instance = ZNet.instance; string arg = ((instance == null) ? null : instance.GetPeer(playerId)?.m_playerName) ?? ""; Log.LogInfo((object)$"Player {arg} ({playerId}) left bed. Players in bed: {playersInBed.Count}"); if (playersInBed.Count == 0) { ResetSequence("all players left bed"); } } } public void OnSleepSuccess() { ResetSequence("sleep succeeded"); } private void ResetSequence(string reason) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown Log.LogInfo((object)("Resetting sequence: " + reason + ".")); sequenceActive = false; sequenceIndex = 0; playersInBed.Clear(); ((MonoBehaviour)this).StopAllCoroutines(); stopLullabyRPC.SendPackage(ZRoutedRpc.Everybody, new ZPackage()); if (!GUIManager.IsHeadless()) { ((MonoBehaviour)this).StartCoroutine(FadeOutMusic(3f)); } } private IEnumerator RunSequence() { while (sequenceActive && sequenceIndex < config.Sequence.Count) { SequenceEntry entry = config.Sequence[sequenceIndex]; yield return (object)new WaitForSeconds((float)entry.Seconds); if (!sequenceActive) { yield break; } BroadcastChatMessage(entry.Message); sequenceIndex++; } if (sequenceActive) { Log.LogInfo((object)"Sequence exhausted."); sequenceActive = false; } } private void BroadcastChatMessage(string text) { if (!((Object)(object)ZNet.instance == (Object)null) && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ShowMessage", new object[2] { 2, text }); Log.LogInfo((object)("[EepyDeepy] " + text)); } } private void OnDestroy() { configWatcher?.Dispose(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } internal static class BedNotify { public static void Enter(string trigger) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)EepyDeepyPlugin.Instance == (Object)null) { return; } if (ZNet.instance.IsServer()) { EepyDeepyPlugin.Instance.OnPlayerBedEnter(ZNet.GetUID(), trigger); return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { EepyDeepyPlugin.Instance.bedEnterRPC.SendPackage(serverPeer.m_uid, new ZPackage()); } } public static void Exit() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)EepyDeepyPlugin.Instance == (Object)null) { return; } if (ZNet.instance.IsServer()) { EepyDeepyPlugin.Instance.OnPlayerBedExit(ZNet.GetUID()); return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { EepyDeepyPlugin.Instance.bedExitRPC.SendPackage(serverPeer.m_uid, new ZPackage()); } } } [HarmonyPatch(typeof(Player), "AttachStart")] public static class Patch_Player_AttachStart { private static void Postfix(Player __instance, bool isBed) { if (isBed && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { EepyDeepyPlugin.Log.LogInfo((object)"Local player got into bed, notifying server."); BedNotify.Enter("entered bed"); } } } [HarmonyPatch(typeof(Player), "AttachStop")] public static class Patch_Player_AttachStop { private static void Prefix(Player __instance, out bool __state) { __state = (Object)(object)__instance == (Object)(object)Player.m_localPlayer && ((Character)__instance).InBed(); } private static void Postfix(bool __state) { if (__state) { EepyDeepyPlugin.Log.LogInfo((object)"Local player got out of bed, notifying server."); BedNotify.Exit(); } } } [HarmonyPatch(typeof(EnvMan), "SkipToMorning")] public static class Patch_EnvMan_SkipToMorning { private static void Postfix() { if (ZNet.instance.IsServer()) { EepyDeepyPlugin.Instance.OnSleepSuccess(); } } } [HarmonyPatch(typeof(Player), "StartEmote")] public static class Patch_Player_StartEmote { private static void Postfix(string emote, Player __instance) { if (!(emote != "rest") && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { EepyDeepyPlugin.Log.LogInfo((object)"Local player used rest emote, notifying server."); BedNotify.Enter("/rest"); } } } [HarmonyPatch(typeof(Player), "StopEmote")] public static class Patch_Player_StopEmote { private static void Postfix(Player __instance) { if (!(Player.LastEmote != "rest") && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { EepyDeepyPlugin.Log.LogInfo((object)"Local player stopped rest emote, notifying server."); BedNotify.Exit(); } } }