Decompiled source of EepyDeepy v1.0.3

plugins/EepyDeepy.dll

Decompiled 4 days ago
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<SequenceEntry> Sequence = new List<SequenceEntry>();
}
[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<long> playersInBed = new HashSet<long>();

	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>();
			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) ?? "<host>";
		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) ?? "<host>";
			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();
		}
	}
}