Decompiled source of EepyDeepy v1.0.2

plugins/EepyDeepy.dll

Decompiled 3 hours 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+6a7c5f189dc219057fbc68de64047530ed67ab4b")]
[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.2")]
[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.2";

	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 DateTime lastBedExit = DateTime.MinValue;

	private bool inBed;

	private int sequenceIndex;

	private bool sequenceActive;

	private int playersInBed;

	private ZNetPeer lastBedPeer;

	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.2 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}.");
		ZNetPeer peer = ZNet.instance.GetPeer(sender);
		OnPlayerBedEnter(peer, "RPC");
		yield break;
	}

	private IEnumerator RPC_OnBedExit(long sender, ZPackage package)
	{
		Log.LogInfo((object)$"RPC_OnBedExit received from {sender}.");
		OnPlayerBedExit();
		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(ZNetPeer peer, string trigger)
	{
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Expected O, but got Unknown
		if (!inBed)
		{
			inBed = true;
			playersInBed++;
			lastBedPeer = peer;
			Log.LogInfo((object)$"Player {peer?.m_playerName} triggered EepyDeepy via {trigger}. Players in bed: {playersInBed}");
			if (!sequenceActive)
			{
				sequenceActive = true;
				sequenceIndex = 0;
				Log.LogInfo((object)("Starting EepyDeepy sequence, triggered by " + peer?.m_playerName + " via " + trigger + "."));
				((MonoBehaviour)this).StartCoroutine(RunSequence());
				playLullabyRPC.SendPackage(ZRoutedRpc.Everybody, new ZPackage());
			}
		}
	}

	public void OnPlayerBedExit()
	{
		if (!inBed)
		{
			return;
		}
		inBed = false;
		if (!((DateTime.Now - lastBedExit).TotalSeconds < 2.0))
		{
			lastBedExit = DateTime.Now;
			playersInBed = Math.Max(0, playersInBed - 1);
			Log.LogInfo((object)$"Player left bed. Players in bed: {playersInBed}");
			if (playersInBed == 0)
			{
				ResetSequence("all players left bed");
			}
		}
	}

	public void OnSleepSuccess()
	{
		ResetSequence("sleep succeeded");
	}

	private void ResetSequence(string reason)
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Expected O, but got Unknown
		Log.LogInfo((object)("Resetting sequence: " + reason + "."));
		inBed = false;
		sequenceActive = false;
		sequenceIndex = 0;
		playersInBed = 0;
		lastBedPeer = null;
		((MonoBehaviour)this).StopAllCoroutines();
		stopLullabyRPC.SendPackage(ZRoutedRpc.Everybody, new ZPackage());
	}

	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();
		}
	}
}
[HarmonyPatch(typeof(Bed), "Interact")]
public static class Patch_Bed_Interact
{
	private static void Postfix(Humanoid human, bool __result)
	{
		if (!ZNet.instance.IsServer() || !__result)
		{
			return;
		}
		ZNetPeer peer = null;
		foreach (ZNetPeer peer2 in ZNet.instance.GetPeers())
		{
			if (peer2.m_playerName == ((Character)human).GetHoverName())
			{
				peer = peer2;
				break;
			}
		}
		EepyDeepyPlugin.Instance.OnPlayerBedEnter(peer, "entered bed");
	}
}
[HarmonyPatch(typeof(Bed), "SetOwner")]
public static class Patch_Bed_SetOwner
{
	private static void Postfix(long uid)
	{
		if (ZNet.instance.IsServer() && uid == 0L)
		{
			EepyDeepyPlugin.Instance.OnPlayerBedExit();
		}
	}
}
[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)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		if (!(emote != "rest"))
		{
			EepyDeepyPlugin.Log.LogInfo((object)("Player " + ((Character)__instance).GetHoverName() + " used rest emote, notifying server."));
			EepyDeepyPlugin.Instance.bedEnterRPC.SendPackage(ZNet.instance.GetServerPeer().m_uid, new ZPackage());
		}
	}
}
[HarmonyPatch(typeof(Player), "StopEmote")]
public static class Patch_Player_StopEmote
{
	private static void Prefix(Player __instance)
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		if (!(Player.LastEmote != "rest"))
		{
			EepyDeepyPlugin.Log.LogInfo((object)("Player " + ((Character)__instance).GetHoverName() + " stopped rest emote, notifying server."));
			EepyDeepyPlugin.Instance.bedExitRPC.SendPackage(ZNet.instance.GetServerPeer().m_uid, new ZPackage());
		}
	}
}