Decompiled source of SeagullStopItNow v1.1.0

plugins/SeagullStopItNow/SeagullStopItNow.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SeagullStopItNow")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+5a95ef9da8a00af81dcd4fa5f9edd93b3bdab183")]
[assembly: AssemblyProduct("ValheimMod-SeagullStopItNow")]
[assembly: AssemblyTitle("SeagullStopItNow")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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;
		}
	}
}
namespace SeagullStopItNow
{
	public class ConfigurationManagerAttributes
	{
		public bool? ShowRangeAsPercent;

		public Action<ConfigEntryBase> CustomDrawer;

		public Func<ConfigEntryBase, bool> CustomDrawerIsAdvanced;

		public bool? Browsable;

		public bool? IsAdvanced;

		public int? Order;
	}
	[BepInPlugin("com.archonite.seagullstopitnow", "Seagull Stop It Now", "1.1.0")]
	public class SeagullPlugin : BaseUnityPlugin
	{
		private class SoundEntry
		{
			public string FileName;

			public int Weight;

			public AudioClip Clip;

			public SoundEntry(string fileName, int weight)
			{
				FileName = fileName;
				Weight = weight;
			}
		}

		private static SeagullPlugin Instance;

		public static readonly string znetEventName = "PlaySeagalStopItNow";

		public static ConfigEntry<bool> BroadcastToMultiplayer;

		public static ConfigEntry<bool> IgnoreOtherPlayersBroadcasts;

		private static List<SoundEntry> deathSounds = new List<SoundEntry>
		{
			new SoundEntry("hmhah.wav", 10),
			new SoundEntry("hmhah2.wav", 10),
			new SoundEntry("stopitnow.wav", 10),
			new SoundEntry("stopitnow2.wav", 10),
			new SoundEntry("thatsgood.wav", 2),
			new SoundEntry("SeagullsStopItNowFull.wav", 1)
		};

		private readonly Harmony harmony = new Harmony("com.archonite.seagullstopitnow");

		private void Awake()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			Instance = this;
			BroadcastToMultiplayer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BroadcastToMultiplayer", true, new ConfigDescription("If enabled, the death sound is broadcast to all players in multiplayer.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = true,
					IsAdvanced = false
				}
			}));
			IgnoreOtherPlayersBroadcasts = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IgnoreOtherPlayersBroadcasts", false, new ConfigDescription("If enabled, you will not hear seagull death sounds triggered by other players in multiplayer.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = true,
					IsAdvanced = false
				}
			}));
			LoadAllAudio();
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SeagullStopItNow has loaded!");
		}

		public static void LogMessage(string msg)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
			}
		}

		private void LoadAllAudio()
		{
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			foreach (SoundEntry deathSound in deathSounds)
			{
				string text = Path.Combine(directoryName, deathSound.FileName);
				deathSound.Clip = LoadWavFile(text);
				if ((Object)(object)deathSound.Clip != (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Successfully loaded {deathSound.FileName} (Duration: {deathSound.Clip.length}s).");
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Failed to load audio from " + text));
				}
			}
		}

		private AudioClip LoadWavFile(string filePath)
		{
			if (!File.Exists(filePath))
			{
				LogMessage("WAV file not found at: " + filePath);
				return null;
			}
			byte[] array = File.ReadAllBytes(filePath);
			if (array.Length < 44)
			{
				LogMessage("File too small to be a valid WAV: " + filePath);
				return null;
			}
			int num = array[22];
			int num2 = BitConverter.ToInt32(array, 24);
			int num3 = array[34];
			int num4 = -1;
			for (int i = 12; i < array.Length - 4; i++)
			{
				if (array[i] == 100 && array[i + 1] == 97 && array[i + 2] == 116 && array[i + 3] == 97)
				{
					num4 = i + 8;
					break;
				}
			}
			if (num4 == -1 || num4 >= array.Length)
			{
				LogMessage("Invalid WAV file (no data chunk found): " + filePath);
				return null;
			}
			int num5 = BitConverter.ToInt32(array, num4 - 4);
			int num6 = num3 / 8;
			if (num6 <= 0)
			{
				num6 = 2;
			}
			int num7 = num5 / num6;
			int num8 = num7 / num;
			float[] array2 = new float[num7];
			switch (num3)
			{
			case 16:
			{
				int num11 = 0;
				int num12 = num4;
				while (num11 < num7 && num12 + 1 < array.Length)
				{
					short num13 = BitConverter.ToInt16(array, num12);
					array2[num11] = (float)num13 / 32768f;
					num11++;
					num12 += 2;
				}
				break;
			}
			case 8:
			{
				int num9 = 0;
				int num10 = num4;
				while (num9 < num7 && num10 < array.Length)
				{
					sbyte b = (sbyte)array[num10];
					array2[num9] = (float)b / 128f;
					num9++;
					num10++;
				}
				break;
			}
			default:
				LogMessage($"Unsupported bits per sample ({num3}) in {filePath}. Must be 16-bit PCM.");
				return null;
			}
			AudioClip val = AudioClip.Create(Path.GetFileNameWithoutExtension(filePath), num8, num, num2, false);
			val.SetData(array2, 0);
			return val;
		}

		public static void PlayDeathSound(Vector3 position)
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			List<SoundEntry> list = deathSounds.FindAll((SoundEntry s) => (Object)(object)s.Clip != (Object)null);
			if (list.Count == 0)
			{
				LogMessage("ERROR: No valid audio clips found to play!");
				return;
			}
			int num = 0;
			foreach (SoundEntry item in list)
			{
				num += item.Weight;
			}
			int num2 = Random.Range(0, num);
			AudioClip val = null;
			foreach (SoundEntry item2 in list)
			{
				if (num2 < item2.Weight)
				{
					val = item2.Clip;
					break;
				}
				num2 -= item2.Weight;
			}
			if ((Object)(object)val != (Object)null)
			{
				LogMessage($"Playing audio clip: {((Object)val).name} at {position}");
				AudioSource.PlayClipAtPoint(val, position, 2f);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	public class Character_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit, out bool __state)
		{
			__state = __instance.GetHealth() > 0f;
		}

		private static void Postfix(Character __instance, HitData hit, bool __state)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (!__state || !(__instance.GetHealth() <= 0f) || !((Object)((Component)__instance).gameObject).name.Contains("Seagal"))
			{
				return;
			}
			Character val = (Character)(((object)((hit != null) ? hit.GetAttacker() : null)) ?? ((object)Player.m_localPlayer));
			if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				SeagullPlugin.LogMessage("Seagal killed via Character damage patch!");
				if (SeagullPlugin.BroadcastToMultiplayer.Value && ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, SeagullPlugin.znetEventName, new object[1] { ((Component)val).transform.position });
				}
				else
				{
					SeagullPlugin.PlayDeathSound(((Component)val).transform.position);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Destructible), "Damage")]
	public class Destructible_Damage_Patch
	{
		private static void Postfix(Destructible __instance, HitData hit)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance != (Object)null) || !((Object)((Component)__instance).gameObject).name.Contains("Seagal"))
			{
				return;
			}
			Character val = (Character)(((object)((hit != null) ? hit.GetAttacker() : null)) ?? ((object)Player.m_localPlayer));
			if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				SeagullPlugin.LogMessage("Seagal killed via Destructible damage patch!");
				if (SeagullPlugin.BroadcastToMultiplayer.Value && ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, SeagullPlugin.znetEventName, new object[1] { ((Component)val).transform.position });
				}
				else
				{
					SeagullPlugin.PlayDeathSound(((Component)val).transform.position);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	public class ZNet_Awake_Patch
	{
		private static void Postfix()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<Vector3>(SeagullPlugin.znetEventName, (Action<long, Vector3>)RPC_PlaySeagalStopItNow);
				SeagullPlugin.LogMessage("Seagal network RPC registered.");
			}
		}

		private static void RPC_PlaySeagalStopItNow(long sender, Vector3 position)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.GetUID() : 0);
			if (sender != num && SeagullPlugin.IgnoreOtherPlayersBroadcasts.Value)
			{
				SeagullPlugin.LogMessage($"Ignored seagull sound broadcast from sender {sender} due to user settings.");
				return;
			}
			SeagullPlugin.LogMessage($"Playing Seagal stop it now sound via network (Sender: {sender})");
			SeagullPlugin.PlayDeathSound(position);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "SeagullStopItNow";

		public const string PLUGIN_NAME = "ValheimMod-SeagullStopItNow";

		public const string PLUGIN_VERSION = "1.1.0";
	}
}