Decompiled source of Coconut Klonk v1.0.6

plugins/com.github.Jackstermax.CoconutKlonk.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CoconutKlonk;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.Jackstermax.CoconutKlonk")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.6.0")]
[assembly: AssemblyInformationalVersion("1.0.6")]
[assembly: AssemblyProduct("com.github.Jackstermax.CoconutKlonk")]
[assembly: AssemblyTitle("CoconutKlonk")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
public class BonkSync : MonoBehaviourPun, IOnEventCallback
{
	public void OnEnable()
	{
		PhotonNetwork.AddCallbackTarget((object)this);
	}

	public void OnDisable()
	{
		PhotonNetwork.RemoveCallbackTarget((object)this);
	}

	public void OnEvent(EventData photonEvent)
	{
		//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_001b: Unknown result type (might be due to invalid IL or missing references)
		if (photonEvent.Code == Plugin.ModEventCodes.BonkSoundEvent)
		{
			Vector3 position = (Vector3)photonEvent.CustomData;
			PlayBonkSound(position);
		}
	}

	private void PlayBonkSound(Vector3 position)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		ManualLogSource? log = Plugin.Log;
		if (log != null)
		{
			log.LogWarning((object)"Playing Klonk Sound Via Event");
		}
		SFX_Instance? klonkSFX = Plugin.klonkSFX;
		if (klonkSFX != null)
		{
			klonkSFX.Play(position);
		}
	}
}
public class MyModConfig
{
	public readonly ConfigEntry<bool> removeKlonkSound;

	public readonly ConfigEntry<float> _SFXVolume;

	public readonly ConfigEntry<float> _SFXRange;

	public MyModConfig(ConfigFile cfg)
	{
		cfg.SaveOnConfigSet = false;
		removeKlonkSound = cfg.Bind<bool>("General", "Removes the Klonk! Sound", false, "If enabled, removes the Klonk! sound (only affects the host).");
		_SFXVolume = cfg.Bind<float>("General", "Klonk Volume", 1f, "Volume of Coconut Klonks.");
		_SFXRange = cfg.Bind<float>("General", "Klonk Sound Range", 95f, "Maximum distance a Coconut Klonk! can be heard from.");
		ClearOrphanedEntries(cfg);
		cfg.Save();
		cfg.SaveOnConfigSet = true;
	}

	private static void ClearOrphanedEntries(ConfigFile cfg)
	{
		PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries");
		Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(cfg);
		dictionary.Clear();
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace CoconutKlonk
{
	[BepInPlugin("com.Jackstermax.peak.CoconutKlonk", "CoconutKlonk", "1.0.6")]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Bonkable), "Awake")]
		private static class BonkableAwake
		{
			[HarmonyPostfix]
			private static void ReplaceBonkSFX(Bonkable __instance, ref SFX_Instance[] ___bonk)
			{
				__instance.item = ((Component)__instance).gameObject.GetComponent<Item>();
				if (__instance?.item?.itemID != 36)
				{
					return;
				}
				SFX_Instance? klonkSFX = Plugin.klonkSFX;
				if ((klonkSFX != null && klonkSFX.clips?.Length <= 0) || BoundConfig == null)
				{
					return;
				}
				if ((Object)(object)sync_Instance == (Object)null)
				{
					Get_SyncInstance();
				}
				if (BoundConfig.removeKlonkSound.Value)
				{
					ManualLogSource? log = Log;
					if (log != null)
					{
						log.LogWarning((object)"Removing Klonk Sound");
					}
					___bonk = Array.Empty<SFX_Instance>();
				}
				else if ((Object)(object)Plugin.klonkSFX != (Object)null)
				{
					List<SFX_Instance> list = new List<SFX_Instance> { Plugin.klonkSFX };
					__instance.bonk = list.ToArray();
				}
			}
		}

		[HarmonyPatch(typeof(Bonkable), "Bonk", new Type[] { typeof(Collision) })]
		private static class BonkableBonk
		{
			[HarmonyPrefix]
			private static void ReplaceBonkSFX(Bonkable __instance, Collision coll)
			{
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_0105: Unknown result type (might be due to invalid IL or missing references)
				//IL_010a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Expected O, but got Unknown
				if (PhotonNetwork.OfflineMode)
				{
					return;
				}
				SFX_Instance? klonkSFX = Plugin.klonkSFX;
				if ((klonkSFX == null || !(klonkSFX.clips?.Length <= 0)) && !((Object)(object)__instance == (Object)null) && __instance?.item?.itemID == 36)
				{
					Character componentInParent = coll.gameObject.GetComponentInParent<Character>();
					if (Object.op_Implicit((Object)(object)componentInParent) && Time.time > __instance.lastBonkedTime + __instance.bonkCooldown)
					{
						PhotonNetwork.RaiseEvent(ModEventCodes.BonkSoundEvent, (object)((Component)__instance).gameObject.transform.position, new RaiseEventOptions
						{
							Receivers = (ReceiverGroup)0
						}, SendOptions.SendReliable);
					}
				}
			}
		}

		internal static class ModEventCodes
		{
			internal static readonly byte BonkSoundEvent = 36;
		}

		public const string Id = "com.Jackstermax.peak.CoconutKlonk";

		private readonly Harmony _harmony = new Harmony("com.Jackstermax.peak.CoconutKlonk");

		internal static SFX_Instance? klonkSFX;

		internal static Plugin? instance;

		internal static BonkSync? sync_Instance;

		private static readonly string _SFXFolderName = "Coconut_SFX";

		private readonly int _SFXLimit = 10;

		private const ushort coconutItem_ID = 36;

		private CancellationTokenSource? _SFXLoad_CTS;

		public static string Name => "CoconutKlonk";

		public static string Version => "1.0.6";

		internal static ManualLogSource? Log { get; private set; }

		internal static MyModConfig? BoundConfig { get; private set; }

		internal static BonkSync Get_SyncInstance()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sync_Instance != (Object)null)
			{
				return sync_Instance;
			}
			sync_Instance = Object.FindFirstObjectByType<BonkSync>();
			if ((Object)(object)sync_Instance == (Object)null)
			{
				sync_Instance = new GameObject("BonkSync Listener Instance").AddComponent<BonkSync>();
				Object.DontDestroyOnLoad((Object)(object)((Component)sync_Instance).gameObject);
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogWarning((object)"New BonkSync Instance Created!");
				}
			}
			return sync_Instance;
		}

		private void Awake()
		{
			Run_Setup();
		}

		private async Task Run_Setup()
		{
			bool _OK_Setup = false;
			try
			{
				_OK_Setup = await Setup_Async();
			}
			catch (Exception ex)
			{
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogError((object)("Setup ERROR: " + ex.Message));
				}
			}
			if (_OK_Setup)
			{
				ManualLogSource? log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Plugin " + Name + " loaded successfully!"));
				}
			}
			else
			{
				ManualLogSource? log3 = Log;
				if (log3 != null)
				{
					log3.LogError((object)("ERROR: Plugin " + Name + " loading failed!"));
				}
			}
			await Task.Yield();
		}

		private async Task<bool> Setup_Async()
		{
			if ((Object)(object)instance != (Object)null && (Object)(object)instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
				return false;
			}
			instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			BoundConfig = new MyModConfig(((BaseUnityPlugin)this).Config);
			Harmony val = new Harmony(Name ?? "");
			val.PatchAll();
			return await Kickoff_LoadKlonkSFX_Async();
		}

		private async Task<bool> Kickoff_LoadKlonkSFX_Async()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = Path.Combine(directoryName, _SFXFolderName);
			if (!Directory.Exists(text))
			{
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogError((object)("Coconut_SFX Sound file directory not found: " + text));
				}
				Directory.CreateDirectory(text);
				return false;
			}
			Cancel_SFXLoad_Task();
			_SFXLoad_CTS = new CancellationTokenSource();
			try
			{
				List<AudioClip> list = await LoadSFX_Task(text, _SFXLoad_CTS.Token);
				if (list.Count <= 0)
				{
					return false;
				}
				Init_SFXClips(list);
				SFX_Instance? obj = klonkSFX;
				return obj != null && obj.clips.Length != 0;
			}
			catch (Exception ex)
			{
				ManualLogSource? log2 = Log;
				if (log2 != null)
				{
					log2.LogError((object)("Loading Catch: " + ex.Message));
				}
			}
			return false;
		}

		private void Cancel_SFXLoad_Task()
		{
			if (_SFXLoad_CTS != null && !_SFXLoad_CTS.IsCancellationRequested)
			{
				_SFXLoad_CTS.Cancel();
				_SFXLoad_CTS.Dispose();
				_SFXLoad_CTS = null;
			}
		}

		private async Task<List<AudioClip>> LoadSFX_Task(string directoryPath, CancellationToken token)
		{
			List<AudioClip> result = new List<AudioClip>();
			List<string> list = Directory.GetFiles(directoryPath, "*.wav").ToList();
			if (list.Count <= 0)
			{
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogInfo((object)("No valid sound files present in: " + directoryPath));
				}
				return result;
			}
			ManualLogSource? log2 = Log;
			if (log2 != null)
			{
				log2.LogInfo((object)("Valid Files Found: " + list.Count));
			}
			int num = Math.Min(list.Count, _SFXLimit);
			List<Task<AudioClip>> list2 = new List<Task<AudioClip>>();
			for (int i = 0; i < num; i++)
			{
				string fileName = list[i];
				list2.Add(LoadAudioClip_Single_Async(fileName, token));
			}
			token.ThrowIfCancellationRequested();
			try
			{
				result = (await Task.WhenAll(list2)).OfType<AudioClip>().ToList();
			}
			catch (Exception ex)
			{
				ManualLogSource? log3 = Log;
				if (log3 != null)
				{
					log3.LogError((object)("Parallel SFX Load Error: " + ex.Message));
				}
				result = new List<AudioClip>();
			}
			ManualLogSource? log4 = Log;
			if (log4 != null)
			{
				log4.LogInfo((object)("Clips found: " + result.Count));
			}
			return result;
		}

		private async Task<AudioClip?> LoadAudioClip_Single_Async(string fileName, CancellationToken token)
		{
			token.ThrowIfCancellationRequested();
			string absoluteUri = new Uri(fileName).AbsoluteUri;
			UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)20);
			try
			{
				Awaiter val = AsyncOperationAwaitableExtensions.GetAwaiter((AsyncOperation)(object)req.SendWebRequest());
				if (!((Awaiter)(ref val)).IsCompleted)
				{
					await val;
					Awaiter val2 = default(Awaiter);
					val = val2;
				}
				((Awaiter)(ref val)).GetResult();
				if ((int)req.result == 2 || (int)req.result == 3)
				{
					ManualLogSource? log = Log;
					if (log != null)
					{
						log.LogError((object)("Error loading: " + fileName + " | " + req.error));
					}
					return null;
				}
				return DownloadHandlerAudioClip.GetContent(req);
			}
			finally
			{
				((IDisposable)req)?.Dispose();
			}
		}

		private void Init_SFXClips(List<AudioClip> clips)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			if (clips != null && clips.Count <= 0)
			{
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogInfo((object)"Aborting load, no audio clips in load list!");
				}
				return;
			}
			klonkSFX = ScriptableObject.CreateInstance<SFX_Instance>();
			klonkSFX.clips = clips?.ToArray();
			klonkSFX.settings = new SFX_Settings
			{
				volume = ((BoundConfig != null) ? BoundConfig._SFXVolume.Value : 1f),
				range = ((BoundConfig != null) ? BoundConfig._SFXRange.Value : 75f)
			};
			ManualLogSource? log2 = Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"Created SO: {(Object)(object)klonkSFX != (Object)null} | Clips Count: {klonkSFX?.clips?.Count()}");
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}