Decompiled source of ConfettiHeadshots v1.0.0

BepInEx/plugins/ConfettiHeadshots/ConfettiHeadshots.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DarkTonic.MasterAudio;
using HarmonyLib;
using HoldfastGame;
using Microsoft.CodeAnalysis;
using RyLib;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 ConfettiHeadshots
{
	[BepInPlugin("com.ryannlt.confettiheadshots", "Confetti Headshots", "1.0.0")]
	[BepInDependency("com.ryannlt.rylib", "1.2.0")]
	public class ConfettiHeadshotsMod : BaseUnityPlugin
	{
		public const string Guid = "com.ryannlt.confettiheadshots";

		private Driver _driver;

		private void Awake()
		{
			Settings.Create(((BaseUnityPlugin)this).Config);
			SettingsTab.Register();
			SceneManager.sceneLoaded += OnSceneLoaded;
			EnsureDriver();
			try
			{
				Harmony.CreateAndPatchAll(typeof(ConfettiHeadshotsMod).Assembly, "com.ryannlt.confettiheadshots");
			}
			catch (Exception ex)
			{
				Log.Error("the headshot hook could not be patched in: " + ex.Message);
			}
			Log.Info("Ready.");
		}

		private void OnDestroy()
		{
			Log.Info("plugin component destroyed");
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			EnsureDriver();
		}

		private void EnsureDriver()
		{
			if ((Object)(object)_driver == (Object)null)
			{
				_driver = Driver.Attach(this);
			}
		}

		internal void Tick()
		{
			Settings.PollForExternalEdits();
		}
	}
	internal sealed class Driver : MonoBehaviour
	{
		internal ConfettiHeadshotsMod Owner;

		internal static Driver Attach(ConfettiHeadshotsMod owner)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("ConfettiHeadshots_Driver");
			Object.DontDestroyOnLoad((Object)(object)val);
			Driver driver = val.AddComponent<Driver>();
			driver.Owner = owner;
			return driver;
		}

		private void Update()
		{
			if (Owner != null)
			{
				Owner.Tick();
			}
		}
	}
	internal static class Log
	{
		private static readonly ManualLogSource Source = Logger.CreateLogSource("ConfettiHeadshots");

		private static readonly HashSet<string> Reported = new HashSet<string>();

		public static void Info(string message)
		{
			Source.LogInfo((object)message);
		}

		public static void Warn(string message)
		{
			Source.LogWarning((object)message);
		}

		public static void Error(string message)
		{
			Source.LogError((object)message);
		}

		public static void Once(string where, Exception error)
		{
			if (Reported.Add(where))
			{
				Source.LogError((object)(where + " failed: " + error));
			}
		}
	}
	internal static class Settings
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<bool> OnlyMyKills;

		public static ConfigEntry<float> Volume;

		public static ConfigEntry<int> ConfettiAmount;

		public static ConfigEntry<float> MaxDistance;

		private static ConfigFile _config;

		private static DateTime _stamp;

		private static float _nextCheck;

		public static void Create(ConfigFile config)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			_config = config;
			Enabled = config.Bind<bool>("General", "Enabled", true, "Confetti and the party sound when a player is killed by a headshot.");
			OnlyMyKills = config.Bind<bool>("General", "OnlyMyKills", false, "Only your own headshot kills set off the confetti. Off, every headshot kill near you does.");
			Volume = config.Bind<float>("General", "Volume", 1f, new ConfigDescription("Volume of the party sound, on top of the game's effects volume. 0 mutes it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ConfettiAmount = config.Bind<int>("General", "ConfettiAmount", 80, new ConfigDescription("Pieces of confetti in each burst. 0 turns the confetti off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 300), Array.Empty<object>()));
			MaxDistance = config.Bind<float>("General", "MaxDistance", 150f, new ConfigDescription("Headshot kills farther than this from your camera, in meters, are skipped.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 500f), Array.Empty<object>()));
			_stamp = Stamp();
		}

		public static void PollForExternalEdits()
		{
			if (_config != null && !(Time.unscaledTime < _nextCheck))
			{
				_nextCheck = Time.unscaledTime + 1f;
				DateTime dateTime = Stamp();
				if (!(dateTime == _stamp))
				{
					_stamp = dateTime;
					_config.Reload();
				}
			}
		}

		private static DateTime Stamp()
		{
			try
			{
				return File.GetLastWriteTimeUtc(_config.ConfigFilePath);
			}
			catch (Exception)
			{
				return _stamp;
			}
		}
	}
	internal static class SettingsTab
	{
		private const string TabName = "Confetti Headshots";

		public static void Register()
		{
			ModTab val = PMenu.ModTab("com.ryannlt.confettiheadshots", "Confetti Headshots", "hui-p-slay", false, (Func<bool>)null);
			if (val != null)
			{
				val.Section("com.ryannlt.confettiheadshots", "Confetti", (Action<Section>)Build);
			}
		}

		private static void Build(Section section)
		{
			section.Toggle("Enabled", Settings.Enabled, "hui-p-slay");
			section.Toggle("Only my kills", Settings.OnlyMyKills, "hui-p-tab-players");
			section.Button("Test", (Action)Party.Test, "hui-p-tab-maps", "Bursts confetti and plays the party sound 3 meters in front of your camera.");
			section.Slider("Volume", Settings.Volume, 0f, 1f, 0.05f, "0.00");
			section.Slider("Confetti amount", Settings.ConfettiAmount, 0, 300);
			section.Slider("Max distance (m)", Settings.MaxDistance, 20f, 500f, 10f, "0");
		}
	}
	internal static class Confetti
	{
		private const int MaxParticles = 1500;

		private const int CollisionLayers = 8705;

		private const float Turn = (float)Math.PI * 2f;

		private static readonly Color[] Palette = (Color[])(object)new Color[7]
		{
			new Color(1f, 0.16f, 0.2f),
			new Color(1f, 0.55f, 0.08f),
			new Color(1f, 0.9f, 0.15f),
			new Color(0.2f, 0.9f, 0.3f),
			new Color(0.15f, 0.85f, 1f),
			new Color(0.25f, 0.4f, 1f),
			new Color(1f, 0.3f, 0.85f)
		};

		private static ParticleSystem _system;

		private static bool _noShader;

		internal static void Burst(Vector3 at, int count)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (count > 0)
			{
				ParticleSystem val = Instance();
				if (!((Object)(object)val == (Object)null))
				{
					((Component)val).transform.SetPositionAndRotation(at, Quaternion.Euler(-90f, 0f, 0f));
					val.Emit(Mathf.Min(count, 1500));
				}
			}
		}

		private static ParticleSystem Instance()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Expected O, but got Unknown
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_system != (Object)null)
			{
				return _system;
			}
			if (_noShader)
			{
				return null;
			}
			Material val = MakeMaterial();
			if ((Object)(object)val == (Object)null)
			{
				_noShader = true;
				return null;
			}
			GameObject val2 = new GameObject("ConfettiHeadshots_Confetti");
			Object.DontDestroyOnLoad((Object)(object)val2);
			ParticleSystem val3 = val2.AddComponent<ParticleSystem>();
			val3.Stop(true, (ParticleSystemStopBehavior)0);
			MainModule main = val3.main;
			((MainModule)(ref main)).playOnAwake = false;
			((MainModule)(ref main)).loop = true;
			((MainModule)(ref main)).duration = 1f;
			((MainModule)(ref main)).maxParticles = 1500;
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
			((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0;
			((MainModule)(ref main)).startLifetime = new MinMaxCurve(2.5f, 4f);
			((MainModule)(ref main)).startSpeed = new MinMaxCurve(4f, 8f);
			((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0.6f);
			((MainModule)(ref main)).startSize3D = true;
			((MainModule)(ref main)).startSizeX = new MinMaxCurve(0.07f, 0.11f);
			((MainModule)(ref main)).startSizeY = new MinMaxCurve(0.035f, 0.055f);
			((MainModule)(ref main)).startSizeZ = MinMaxCurve.op_Implicit(1f);
			((MainModule)(ref main)).startRotation3D = true;
			((MainModule)(ref main)).startRotationX = new MinMaxCurve(0f, (float)Math.PI * 2f);
			((MainModule)(ref main)).startRotationY = new MinMaxCurve(0f, (float)Math.PI * 2f);
			((MainModule)(ref main)).startRotationZ = new MinMaxCurve(0f, (float)Math.PI * 2f);
			MinMaxGradient startColor = default(MinMaxGradient);
			((MinMaxGradient)(ref startColor))..ctor(Colors());
			((MinMaxGradient)(ref startColor)).mode = (ParticleSystemGradientMode)4;
			((MainModule)(ref main)).startColor = startColor;
			EmissionModule emission = val3.emission;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f);
			ShapeModule shape = val3.shape;
			((ShapeModule)(ref shape)).enabled = true;
			((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4;
			((ShapeModule)(ref shape)).angle = 35f;
			((ShapeModule)(ref shape)).radius = 0.08f;
			AnimationCurve val4 = new AnimationCurve((Keyframe[])(object)new Keyframe[3]
			{
				new Keyframe(0f, 8f),
				new Keyframe(0.2f, 1.4f),
				new Keyframe(1f, 1.2f)
			});
			LimitVelocityOverLifetimeModule limitVelocityOverLifetime = val3.limitVelocityOverLifetime;
			((LimitVelocityOverLifetimeModule)(ref limitVelocityOverLifetime)).enabled = true;
			((LimitVelocityOverLifetimeModule)(ref limitVelocityOverLifetime)).limit = new MinMaxCurve(1f, val4);
			((LimitVelocityOverLifetimeModule)(ref limitVelocityOverLifetime)).dampen = 0.15f;
			NoiseModule noise = val3.noise;
			((NoiseModule)(ref noise)).enabled = true;
			((NoiseModule)(ref noise)).strength = MinMaxCurve.op_Implicit(0.6f);
			((NoiseModule)(ref noise)).frequency = 0.8f;
			((NoiseModule)(ref noise)).scrollSpeed = MinMaxCurve.op_Implicit(0.5f);
			((NoiseModule)(ref noise)).quality = (ParticleSystemNoiseQuality)0;
			RotationOverLifetimeModule rotationOverLifetime = val3.rotationOverLifetime;
			((RotationOverLifetimeModule)(ref rotationOverLifetime)).enabled = true;
			((RotationOverLifetimeModule)(ref rotationOverLifetime)).separateAxes = true;
			((RotationOverLifetimeModule)(ref rotationOverLifetime)).x = new MinMaxCurve(-6f, 6f);
			((RotationOverLifetimeModule)(ref rotationOverLifetime)).y = new MinMaxCurve(-6f, 6f);
			((RotationOverLifetimeModule)(ref rotationOverLifetime)).z = new MinMaxCurve(-6f, 6f);
			AnimationCurve val5 = new AnimationCurve((Keyframe[])(object)new Keyframe[3]
			{
				new Keyframe(0f, 1f),
				new Keyframe(0.85f, 1f),
				new Keyframe(1f, 0f)
			});
			SizeOverLifetimeModule sizeOverLifetime = val3.sizeOverLifetime;
			((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true;
			((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, val5);
			CollisionModule collision = val3.collision;
			((CollisionModule)(ref collision)).enabled = true;
			((CollisionModule)(ref collision)).type = (ParticleSystemCollisionType)1;
			((CollisionModule)(ref collision)).mode = (ParticleSystemCollisionMode)0;
			((CollisionModule)(ref collision)).collidesWith = LayerMask.op_Implicit(8705);
			((CollisionModule)(ref collision)).quality = (ParticleSystemCollisionQuality)0;
			((CollisionModule)(ref collision)).dampen = MinMaxCurve.op_Implicit(0.8f);
			((CollisionModule)(ref collision)).bounce = MinMaxCurve.op_Implicit(0.1f);
			((CollisionModule)(ref collision)).lifetimeLoss = MinMaxCurve.op_Implicit(0f);
			((CollisionModule)(ref collision)).radiusScale = 0.5f;
			ParticleSystemRenderer component = val2.GetComponent<ParticleSystemRenderer>();
			component.renderMode = (ParticleSystemRenderMode)4;
			component.mesh = Resources.GetBuiltinResource<Mesh>("Quad.fbx");
			component.alignment = (ParticleSystemRenderSpace)1;
			((Renderer)component).sharedMaterial = val;
			((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)component).receiveShadows = false;
			component.enableGPUInstancing = true;
			val3.Play(true);
			_system = val3;
			return val3;
		}

		private static Gradient Colors()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			GradientColorKey[] array = (GradientColorKey[])(object)new GradientColorKey[Palette.Length];
			for (int i = 0; i < Palette.Length; i++)
			{
				array[i] = new GradientColorKey(Palette[i], ((float)i + 1f) / (float)Palette.Length);
			}
			Gradient val = new Gradient();
			val.mode = (GradientMode)1;
			val.SetKeys(array, (GradientAlphaKey[])(object)new GradientAlphaKey[2]
			{
				new GradientAlphaKey(1f, 0f),
				new GradientAlphaKey(1f, 1f)
			});
			return val;
		}

		private static Material MakeMaterial()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Universal Render Pipeline/Particles/Unlit");
			if ((Object)(object)val == (Object)null)
			{
				val = Loaded("Particles/Unlit");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Sprites/Default");
			}
			if ((Object)(object)val == (Object)null)
			{
				Log.Warn("no particle shader was found, so confetti is off. The party sound still plays.");
				return null;
			}
			Material val2 = new Material(val);
			((Object)val2).name = "ConfettiHeadshots Confetti";
			((Object)val2).hideFlags = (HideFlags)32;
			Texture2D whiteTexture = Texture2D.whiteTexture;
			if (val2.HasProperty("_BaseMap"))
			{
				val2.SetTexture("_BaseMap", (Texture)(object)whiteTexture);
			}
			if (val2.HasProperty("_MainTex"))
			{
				val2.SetTexture("_MainTex", (Texture)(object)whiteTexture);
			}
			if (val2.HasProperty("_BaseColor"))
			{
				val2.SetColor("_BaseColor", Color.white);
			}
			if (val2.HasProperty("_Color"))
			{
				val2.SetColor("_Color", Color.white);
			}
			if (val2.HasProperty("_Cull"))
			{
				val2.SetFloat("_Cull", 0f);
			}
			Log.Info("confetti uses the " + ((Object)val).name + " shader.");
			return val2;
		}

		private static Shader Loaded(string part)
		{
			Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null && ((Object)array[i]).name.Contains(part))
				{
					return array[i];
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(ClientPlayerDamageManager), "_UpdatePlayerHealth")]
	internal static class HeadshotPatch
	{
		private const float HeadHeight = 1.6f;

		private static void Postfix(RoundPlayer hitPlayer, PlayerHealthChangedEventArgs playerHealthChangedEventArgs)
		{
			try
			{
				Check(hitPlayer, playerHealthChangedEventArgs);
			}
			catch (Exception error)
			{
				Log.Once("headshot check", error);
			}
		}

		private static void Check(RoundPlayer victim, PlayerHealthChangedEventArgs args)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if (!Settings.Enabled.Value || args == null || !((EntityHealthChangedEventArgs<PlayerHealthChangedPacket>)(object)args).WasPlayerKilled)
			{
				return;
			}
			PlayerHealthChangedData changedData = ((EntityHealthChangedEventArgs<PlayerHealthChangedPacket>)(object)args).ChangedData;
			ShotByFirearmPlayerHealthChangedData val = (ShotByFirearmPlayerHealthChangedData)(object)((changedData is ShotByFirearmPlayerHealthChangedData) ? changedData : null);
			if (val != null && (int)val.HumanoidHitboxType == 1 && (!Settings.OnlyMyKills.Value || val.FiringPlayerID == Party.LocalPlayerId))
			{
				Vector3 val2 = val.HitWorldPosition;
				if (val2 == Vector3.zero && victim != null)
				{
					val2 = victim.PlayerTransformData.position + Vector3.up * 1.6f;
				}
				if (!(val2 == Vector3.zero))
				{
					Party.Burst(val2);
				}
			}
		}
	}
	internal static class Party
	{
		private const float TestDistance = 3f;

		internal static int LocalPlayerId
		{
			get
			{
				ClientComponentReferenceManager clientInstance = ClientComponentReferenceManager.ClientInstance;
				if ((Object)(object)clientInstance == (Object)null || (Object)(object)clientInstance.clientRoundPlayerManager == (Object)null || clientInstance.clientRoundPlayerManager.LocalPlayer == null)
				{
					return -1;
				}
				return ((RoundPlayer)clientInstance.clientRoundPlayerManager.LocalPlayer).NetworkPlayerID;
			}
		}

		private static Camera ActiveCamera
		{
			get
			{
				ClientComponentReferenceManager clientInstance = ClientComponentReferenceManager.ClientInstance;
				if ((Object)(object)clientInstance != (Object)null && (Object)(object)clientInstance.ownerCameraManager != (Object)null)
				{
					Camera val = clientInstance.ownerCameraManager.ActiveCamera;
					if ((Object)(object)val == (Object)null)
					{
						val = clientInstance.ownerCameraManager.ownerCamera;
					}
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
				return Camera.main;
			}
		}

		internal static void Burst(Vector3 head)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Camera activeCamera = ActiveCamera;
			float value = Settings.MaxDistance.Value;
			if ((Object)(object)activeCamera != (Object)null)
			{
				Vector3 val = ((Component)activeCamera).transform.position - head;
				if (((Vector3)(ref val)).sqrMagnitude > value * value)
				{
					return;
				}
			}
			Fire(head);
		}

		internal static void Test()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Camera activeCamera = ActiveCamera;
			if (!((Object)(object)activeCamera == (Object)null))
			{
				Fire(((Component)activeCamera).transform.position + ((Component)activeCamera).transform.forward * 3f);
			}
		}

		private static void Fire(Vector3 at)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Confetti.Burst(at, Settings.ConfettiAmount.Value);
			}
			catch (Exception error)
			{
				Log.Once("confetti", error);
			}
			try
			{
				Sound.Play(at, Settings.Volume.Value);
			}
			catch (Exception error2)
			{
				Log.Once("party sound", error2);
			}
		}
	}
	internal static class Sound
	{
		private const string Resource = "ConfettiHeadshots.Sounds.party.wav";

		private const string NapoleonicGroup = "Headshot Sound NaW";

		private const string FrontlinesGroup = "Headshot Sound";

		private const int PoolSize = 4;

		private static readonly AudioSource[] Pool = (AudioSource[])(object)new AudioSource[4];

		private static AudioClip _clip;

		private static bool _failed;

		private static GameObject _root;

		private static int _next;

		private static bool _styleLogged;

		private static bool Frontlines
		{
			get
			{
				ClientComponentReferenceManager clientInstance = ClientComponentReferenceManager.ClientInstance;
				if ((Object)(object)clientInstance == (Object)null || (Object)(object)clientInstance.clientGameManager == (Object)null || clientInstance.clientGameManager.CurrentRoundGameDetails == null)
				{
					return false;
				}
				return clientInstance.clientGameManager.CurrentRoundGameDetails.FrontlinesMode;
			}
		}

		internal static void Play(Vector3 at, float volume)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (volume <= 0f)
			{
				return;
			}
			AudioClip val = Clip();
			if (!((Object)(object)val == (Object)null))
			{
				AudioSource val2 = Next();
				if (!((Object)(object)val2 == (Object)null))
				{
					Style(val2);
					((Component)val2).transform.position = at;
					val2.clip = val;
					val2.volume = Mathf.Clamp01(volume);
					val2.Play();
				}
			}
		}

		private static AudioClip Clip()
		{
			if ((Object)(object)_clip != (Object)null || _failed)
			{
				return _clip;
			}
			try
			{
				byte[] array;
				using (Stream stream = typeof(Sound).Assembly.GetManifestResourceStream("ConfettiHeadshots.Sounds.party.wav"))
				{
					if (stream == null)
					{
						throw new InvalidOperationException("ConfettiHeadshots.Sounds.party.wav is missing from the DLL.");
					}
					array = new byte[stream.Length];
					int num;
					for (int i = 0; i < array.Length; i += num)
					{
						num = stream.Read(array, i, array.Length - i);
						if (num <= 0)
						{
							break;
						}
					}
				}
				int channels;
				int rate;
				float[] array2 = Wav.Decode(array, out channels, out rate);
				_clip = AudioClip.Create("ConfettiHeadshots Party", array2.Length / channels, channels, rate, false);
				_clip.SetData(array2, 0);
				((Object)_clip).hideFlags = (HideFlags)32;
				Log.Info("party sound loaded: " + array2.Length / channels + " samples at " + rate + " Hz, " + channels + " channel(s).");
			}
			catch (Exception ex)
			{
				_failed = true;
				Log.Error("the party sound could not be loaded, so only the confetti shows: " + ex.Message);
			}
			return _clip;
		}

		private static AudioSource Next()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			if ((Object)(object)_root == (Object)null || (Object)(object)Pool[0] == (Object)null)
			{
				_root = new GameObject("ConfettiHeadshots_Sound");
				Object.DontDestroyOnLoad((Object)(object)_root);
				for (int i = 0; i < 4; i++)
				{
					GameObject val = new GameObject("Source " + i);
					val.transform.SetParent(_root.transform, false);
					AudioSource val2 = val.AddComponent<AudioSource>();
					val2.playOnAwake = false;
					val2.loop = false;
					Pool[i] = val2;
				}
			}
			AudioSource result = Pool[_next];
			_next = (_next + 1) % 4;
			return result;
		}

		private static void Style(AudioSource source)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Invalid comparison between Unknown and I4
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			AudioSource val = GameSource();
			if ((Object)(object)val == (Object)null)
			{
				source.spatialBlend = 1f;
				source.rolloffMode = (AudioRolloffMode)0;
				source.minDistance = 5f;
				source.maxDistance = 120f;
				return;
			}
			source.outputAudioMixerGroup = val.outputAudioMixerGroup;
			source.spatialBlend = val.spatialBlend;
			source.rolloffMode = val.rolloffMode;
			source.minDistance = val.minDistance;
			source.maxDistance = val.maxDistance;
			source.spread = val.spread;
			source.dopplerLevel = val.dopplerLevel;
			source.reverbZoneMix = val.reverbZoneMix;
			source.priority = val.priority;
			if ((int)val.rolloffMode == 2)
			{
				source.SetCustomCurve((AudioSourceCurveType)0, val.GetCustomCurve((AudioSourceCurveType)0));
			}
			if (!_styleLogged)
			{
				_styleLogged = true;
				Log.Info("party sound uses the game's headshot sound settings: mixer " + (((Object)(object)val.outputAudioMixerGroup != (Object)null) ? ((Object)val.outputAudioMixerGroup).name : "none") + ", " + ((object)val.rolloffMode/*cast due to .constrained prefix*/).ToString() + " rolloff, " + val.minDistance + " to " + val.maxDistance + " m.");
			}
		}

		private static AudioSource GameSource()
		{
			try
			{
				MasterAudioGroup val = MasterAudio.GrabGroup(Frontlines ? "Headshot Sound" : "Headshot Sound NaW", false);
				if ((Object)(object)val == (Object)null || val.groupVariations == null)
				{
					return null;
				}
				for (int i = 0; i < val.groupVariations.Count; i++)
				{
					SoundGroupVariation val2 = val.groupVariations[i];
					if ((Object)(object)val2 != (Object)null && (Object)(object)val2.VarAudio != (Object)null)
					{
						return val2.VarAudio;
					}
				}
			}
			catch (Exception)
			{
				return null;
			}
			return null;
		}
	}
	internal static class Wav
	{
		internal static float[] Decode(byte[] bytes, out int channels, out int rate)
		{
			channels = 0;
			rate = 0;
			if (bytes == null || bytes.Length < 12 || Tag(bytes, 0) != "RIFF" || Tag(bytes, 8) != "WAVE")
			{
				throw new FormatException("not a RIFF WAVE file.");
			}
			int num = 0;
			int num2 = 12;
			while (num2 + 8 <= bytes.Length)
			{
				string text = Tag(bytes, num2);
				int num3 = BitConverter.ToInt32(bytes, num2 + 4);
				int num4 = num2 + 8;
				if (num3 < 0 || num4 + num3 > bytes.Length)
				{
					num3 = bytes.Length - num4;
				}
				if (text == "fmt ")
				{
					int num5 = BitConverter.ToInt16(bytes, num4);
					if (num5 != 1)
					{
						throw new FormatException("only PCM is supported, this is format " + num5 + ".");
					}
					channels = BitConverter.ToInt16(bytes, num4 + 2);
					rate = BitConverter.ToInt32(bytes, num4 + 4);
					num = BitConverter.ToInt16(bytes, num4 + 14);
				}
				else if (text == "data")
				{
					if (channels <= 0 || rate <= 0)
					{
						throw new FormatException("the data chunk comes before the format chunk.");
					}
					if (num != 16)
					{
						throw new FormatException("only 16 bit samples are supported, this has " + num + ".");
					}
					int num6 = num3 / 2;
					float[] array = new float[num6];
					for (int i = 0; i < num6; i++)
					{
						array[i] = (float)BitConverter.ToInt16(bytes, num4 + i * 2) / 32768f;
					}
					return array;
				}
				num2 = num4 + num3 + (num3 & 1);
			}
			throw new FormatException("no data chunk was found.");
		}

		private static string Tag(byte[] bytes, int offset)
		{
			return Encoding.ASCII.GetString(bytes, offset, 4);
		}
	}
}