Decompiled source of AvatarStatExtender v1.0.0

Mods/AvatarStatExtender.dll

Decompiled 9 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using System.Threading;
using AvatarStatExtender;
using AvatarStatExtender.API;
using AvatarStatExtender.BuiltInEvents;
using AvatarStatExtender.Components;
using AvatarStatExtender.Data;
using AvatarStatExtender.Tools;
using AvatarStatExtender.Tools.Assets;
using BoneLib;
using FieldInjector;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using SLZ.Marrow.Data;
using SLZ.Marrow.Warehouse;
using SLZ.Rig;
using SLZ.VRMK;
using UnhollowerBaseLib;
using UnhollowerBaseLib.Attributes;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.SceneManagement;
using XansTools.AvatarInteroperability;
using XansTools.Data;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("AvatarStatExtender")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AvatarStatExtender")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("74cf3aaf-5536-4556-9992-906c2cdb571b")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: MelonInfo(typeof(AvatarStatExtensionMod), "Extended Avatar Driver", "1.0.0", "Xan", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 AvatarExtendedAudioContainer : MonoBehaviour
{
	public string[] names = Array.Empty<string>();

	public SerializableAudioArray2D sounds = new SerializableAudioArray2D();

	public AudioClip[] allOfTheSounds = Array.Empty<AudioClip>();

	public int[] lengthsOfEachSegment = Array.Empty<int>();

	public AudioEventType[] eventTypes = Array.Empty<AudioEventType>();

	public AudioPlayType[] playTypes = Array.Empty<AudioPlayType>();

	public string?[] customEventTypes = Array.Empty<string>();

	public string?[] customPlayTypes = Array.Empty<string>();

	public Vector2[] pitchRanges = Array.Empty<Vector2>();

	public float[] volumes = Array.Empty<float>();

	public AudioMixerTarget[] mixers = Array.Empty<AudioMixerTarget>();

	public SoundFlags[] soundFlags = Array.Empty<SoundFlags>();

	public AudioSource?[] templateSources = Array.Empty<AudioSource>();

	private IReadOnlyList<ReadOnlyAudioEntry>? _ROEntriesCache;

	internal List<AudioEntry> Entries
	{
		[HideFromIl2Cpp]
		get;
		[HideFromIl2Cpp]
		private set;
	} = new List<AudioEntry>();


	public AvatarExtendedAudioContainer(IntPtr @this)
		: base(@this)
	{
	}

	public void EnsureSymmetry()
	{
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		int val = names.Length;
		val = Math.Max(val, names.Length);
		val = Math.Max(val, sounds.Children.Length);
		val = Math.Max(val, eventTypes.Length);
		val = Math.Max(val, playTypes.Length);
		val = Math.Max(val, customEventTypes.Length);
		val = Math.Max(val, customPlayTypes.Length);
		val = Math.Max(val, pitchRanges.Length);
		val = Math.Max(val, volumes.Length);
		val = Math.Max(val, mixers.Length);
		val = Math.Max(val, soundFlags.Length);
		val = Math.Max(val, templateSources.Length);
		Tools.ResizeArrayDefault(ref names, val, "New Sound Group");
		Tools.ResizeArrayDefault(ref sounds.children, val, new SerializableAudioArray());
		Tools.ResizeArrayDefault(ref eventTypes, val, AudioEventType.HitBullet);
		Tools.ResizeArrayDefault(ref playTypes, val, AudioPlayType.Random);
		Tools.ResizeArrayDefault(ref customEventTypes, val, null);
		Tools.ResizeArrayDefault(ref customPlayTypes, val, null);
		Tools.ResizeArrayDefault(ref pitchRanges, val, new Vector2(1f, 1f));
		Tools.ResizeArrayDefault(ref volumes, val, 0.5f);
		Tools.ResizeArrayDefault(ref mixers, val, AudioMixerTarget.SFX);
		Tools.ResizeArrayDefault(ref soundFlags, val, SoundFlags.RealtimePitchShift);
		Tools.ResizeArrayDefault(ref templateSources, val, null);
	}

	public void Sounds2DToAbyssmalMappedArray()
	{
		List<AudioClip> list = new List<AudioClip>(128);
		List<int> list2 = new List<int>(128);
		SerializableAudioArray[] children = sounds.Children;
		foreach (SerializableAudioArray serializableAudioArray in children)
		{
			list.AddRange(serializableAudioArray.clips);
			list2.Add(serializableAudioArray.clips.Count);
		}
		allOfTheSounds = list.ToArray();
		lengthsOfEachSegment = list2.ToArray();
	}

	public void AbyssmalMappedArrayToSounds2D()
	{
		sounds.Children = new SerializableAudioArray[lengthsOfEachSegment.Length];
		int num = 0;
		for (int i = 0; i < lengthsOfEachSegment.Length; i++)
		{
			int num2 = lengthsOfEachSegment[i];
			sounds.Children[i] = new SerializableAudioArray();
			for (int j = 0; j < num2; j++)
			{
				sounds.Children[i].clips.Add(allOfTheSounds[num + j]);
			}
			num += num2;
		}
	}

	[HideFromIl2Cpp]
	internal IReadOnlyList<ReadOnlyAudioEntry> GetEntries()
	{
		if (_ROEntriesCache == null)
		{
			AbyssmalMappedArrayToSounds2D();
			UpdateEntries();
			_ROEntriesCache = new ReadOnlyCollection<ReadOnlyAudioEntry>(Entries.Select((AudioEntry entry) => new ReadOnlyAudioEntry(entry)).ToList());
		}
		return _ROEntriesCache;
	}

	public void UpdateEntries()
	{
		Entries = this.EntriesFromContainer().ToList();
	}
}
public class AvatarStatDriver : MonoBehaviour
{
	public bool useCustomStats;

	public bool useCustomMass;

	public bool useProportionalMassEditing;

	public bool useCustomAgility;

	public bool useCustomSpeed;

	public bool useCustomUpper;

	public bool useCustomLower;

	public bool useCustomVitality;

	public bool useCustomIntelligence;

	public float customAgility;

	public float customSpeed;

	public float customUpper;

	public float customLower;

	public float customVitality;

	public float customIntelligence;

	public bool useCustomChestMass;

	public bool useCustomPelvisMass;

	public bool useCustomArmMass;

	public bool useCustomLegMass;

	public bool useCustomHeadMass;

	public float customTotalMass;

	public float customChestMass;

	public float customPelvisMass;

	public float customArmMass;

	public float customLegMass;

	public float customHeadMass;

	public float extraJumpVerticalVelocity;

	[AllowNull]
	private Avatar _avatar;

	public float VanillaAgility
	{
		get
		{
			_avatar.ComputeAllStats(out var _, out var stats);
			return stats.agility;
		}
	}

	public float VanillaSpeed
	{
		get
		{
			_avatar.ComputeAllStats(out var _, out var stats);
			return stats.speed;
		}
	}

	public float VanillaUpperStrength
	{
		get
		{
			_avatar.ComputeAllStats(out var _, out var stats);
			return stats.strengthUpper;
		}
	}

	public float VanillaLowerStrength
	{
		get
		{
			_avatar.ComputeAllStats(out var _, out var stats);
			return stats.strengthLower;
		}
	}

	public float VanillaVitality
	{
		get
		{
			_avatar.ComputeAllStats(out var _, out var stats);
			return stats.vitality;
		}
	}

	public float VanillaIntelligence
	{
		get
		{
			_avatar.ComputeAllStats(out var _, out var stats);
			return stats.intelligence;
		}
	}

	public float VanillaTotalMass
	{
		get
		{
			AvatarStatCalculationExtension.AvatarComputationProperties additionalInfo;
			return _avatar.ComputeMass(out additionalInfo).massTotal;
		}
	}

	public float VanillaChestMass
	{
		get
		{
			AvatarStatCalculationExtension.AvatarComputationProperties additionalInfo;
			return _avatar.ComputeMass(out additionalInfo).massChest;
		}
	}

	public float VanillaPelvisMass
	{
		get
		{
			AvatarStatCalculationExtension.AvatarComputationProperties additionalInfo;
			return _avatar.ComputeMass(out additionalInfo).massPelvis;
		}
	}

	public float VanillaArmMass
	{
		get
		{
			AvatarStatCalculationExtension.AvatarComputationProperties additionalInfo;
			return _avatar.ComputeMass(out additionalInfo).massArm;
		}
	}

	public float VanillaLegMass
	{
		get
		{
			AvatarStatCalculationExtension.AvatarComputationProperties additionalInfo;
			return _avatar.ComputeMass(out additionalInfo).massLeg;
		}
	}

	public float VanillaHeadMass
	{
		get
		{
			AvatarStatCalculationExtension.AvatarComputationProperties additionalInfo;
			return _avatar.ComputeMass(out additionalInfo).massHead;
		}
	}

	public float EffectiveAgility
	{
		get
		{
			if (useCustomStats && useCustomAgility)
			{
				return customAgility;
			}
			return VanillaAgility;
		}
	}

	public float EffectiveSpeed
	{
		get
		{
			if (useCustomStats && useCustomSpeed)
			{
				return customSpeed;
			}
			return VanillaSpeed;
		}
	}

	public float EffectiveUpperStrength
	{
		get
		{
			if (useCustomStats && useCustomUpper)
			{
				return customUpper;
			}
			return VanillaUpperStrength;
		}
	}

	public float EffectiveLowerStrength
	{
		get
		{
			if (useCustomStats && useCustomLower)
			{
				return customLower;
			}
			return VanillaLowerStrength;
		}
	}

	public float EffectiveVitality
	{
		get
		{
			if (useCustomStats && useCustomVitality)
			{
				return customVitality;
			}
			return VanillaVitality;
		}
	}

	public float EffectiveIntelligence
	{
		get
		{
			if (useCustomStats && useCustomIntelligence)
			{
				return customIntelligence;
			}
			return VanillaIntelligence;
		}
	}

	public float MassProportion
	{
		get
		{
			if (useCustomMass && useProportionalMassEditing)
			{
				AvatarStatCalculationExtension.AvatarComputationProperties additionalInfo;
				AvatarStatCalculationExtension.AvatarMasses avatarMasses = _avatar.ComputeMass(out additionalInfo);
				return customTotalMass / avatarMasses.massTotal;
			}
			return 1f;
		}
	}

	public float EffectiveTotalMass
	{
		get
		{
			if (useCustomMass)
			{
				if (useProportionalMassEditing)
				{
					return customTotalMass;
				}
				return EffectiveChestMass + EffectivePelvisMass + EffectiveArmMass * 2f + EffectiveLegMass * 2f + EffectiveHeadMass;
			}
			return VanillaTotalMass;
		}
	}

	public float EffectivePelvisMass
	{
		get
		{
			if (useCustomMass)
			{
				if (useProportionalMassEditing && useCustomPelvisMass)
				{
					return VanillaPelvisMass * MassProportion;
				}
				if (useCustomPelvisMass)
				{
					return customPelvisMass;
				}
			}
			return VanillaPelvisMass;
		}
	}

	public float EffectiveChestMass
	{
		get
		{
			if (useCustomMass)
			{
				if (useProportionalMassEditing && useCustomChestMass)
				{
					return VanillaChestMass * MassProportion;
				}
				if (useCustomChestMass)
				{
					return customChestMass;
				}
			}
			return VanillaChestMass;
		}
	}

	public float EffectiveArmMass
	{
		get
		{
			if (useCustomMass)
			{
				if (useProportionalMassEditing && useCustomArmMass)
				{
					return VanillaArmMass * MassProportion;
				}
				if (useCustomArmMass)
				{
					return customArmMass;
				}
			}
			return VanillaArmMass;
		}
	}

	public float EffectiveLegMass
	{
		get
		{
			if (useCustomMass)
			{
				if (useProportionalMassEditing && useCustomLegMass)
				{
					return VanillaLegMass * MassProportion;
				}
				if (useCustomLegMass)
				{
					return customLegMass;
				}
			}
			return VanillaLegMass;
		}
	}

	public float EffectiveHeadMass
	{
		get
		{
			if (useCustomMass)
			{
				if (useProportionalMassEditing && useCustomHeadMass)
				{
					return VanillaHeadMass * MassProportion;
				}
				if (useCustomHeadMass)
				{
					return customHeadMass;
				}
			}
			return VanillaHeadMass;
		}
	}

	public AvatarStatDriver(IntPtr @this)
		: base(@this)
	{
	}

	private void Awake()
	{
		_avatar = ((Component)this).GetComponent<Avatar>();
	}
}
namespace AvatarStatExtender
{
	internal class AvatarStatExtensionMod : MelonMod
	{
		public override void OnInitializeMelon()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			((MelonBase)this).OnInitializeMelon();
			Prefs.Initialize();
			Log.Initialize(((MelonBase)this).LoggerInstance);
			Log.Info("Initializing the avatar extender...");
			if (Prefs.TraceLogging)
			{
				Log.Warn("TRACE LOGGING IS ENABLED. Your log will be spammed with highly verbose debug statements.");
				Log.Warn("You can disable trace logging in the mod's preferences.");
			}
			Log.Debug("Creating Harmony...");
			Harmony harmony = new Harmony("Extended Avatar Driver");
			Log.Debug("Injecting fields from the stat component...");
			SerialisationHandler.Inject<AvatarStatDriver>(0);
			SerialisationHandler.Inject<AvatarExtendedAudioContainer>(0);
			Log.Debug("Injection complete. Preparing the stat marshaller and audio driver...");
			StatMarshaller.Initialize(harmony);
			SoundBroadcastMarshaller.Initialize();
		}
	}
	public static class Log
	{
		[AllowNull]
		private static Instance _log;

		internal static void Initialize(Instance log)
		{
			_log = log;
		}

		public static void Info(object msg)
		{
			_log.Msg(msg);
		}

		public static void Info(string msg)
		{
			_log.Msg(msg);
		}

		public static void Warn(object msg)
		{
			_log.Warning(msg);
		}

		public static void Warn(string msg)
		{
			_log.Warning(msg);
		}

		public static void Error(object msg)
		{
			_log.Error(msg);
		}

		public static void Error(string msg)
		{
			_log.Error(msg);
		}

		public static void Debug(object msg)
		{
			_log.Msg(ConsoleColor.Gray, $"[DEBUG] {msg}");
		}

		public static void Debug(string msg)
		{
			_log.Msg(ConsoleColor.Gray, "[DEBUG] " + msg);
		}

		public static void Trace(object msg)
		{
			if (Prefs.TraceLogging)
			{
				_log.Msg(ConsoleColor.DarkGray, $"[TRACE] {msg}");
			}
		}

		public static void Trace(string msg)
		{
			if (Prefs.TraceLogging)
			{
				_log.Msg(ConsoleColor.DarkGray, "[TRACE] " + msg);
			}
		}
	}
	internal static class Prefs
	{
		private static MelonPreferences_Entry<bool> _traceLogging;

		public static bool TraceLogging => _traceLogging.Value;

		internal static void Initialize()
		{
			MelonPreferences_Category val = MelonPreferences.CreateCategory("extendedAvyDriver_main");
			val.DisplayName = "Main Settings";
			_traceLogging = val.CreateEntry<bool>("traceLogging", true, "Trace Logging", "Trace Logging causes extremely (like, comically) specific things to be written into the console." + Environment.NewLine + "This tends to flood the console with information that is useless normally, but it is very useful for debugging.", false, false, (ValueValidator)null, (string)null);
		}
	}
}
namespace AvatarStatExtender.Tools
{
	public static class ListTools
	{
		private sealed class StubbedListImpl<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IReadOnlyList<T>, IReadOnlyCollection<T>
		{
			private sealed class EmptyEnumerator : IEnumerator<T>, IDisposable, IEnumerator
			{
				public T Current { get; } = default(T);


				object IEnumerator.Current => Current;

				public void Dispose()
				{
				}

				public bool MoveNext()
				{
					return false;
				}

				public void Reset()
				{
				}
			}

			public static readonly IReadOnlyList<T> INSTANCE = new StubbedListImpl<T>();

			private static readonly EmptyEnumerator EMPTY_ENUMERATOR = new EmptyEnumerator();

			public T this[int index]
			{
				get
				{
					throw new IndexOutOfRangeException();
				}
			}

			T IList<T>.this[int index]
			{
				get
				{
					throw new IndexOutOfRangeException();
				}
				set
				{
					throw new NotSupportedException();
				}
			}

			public int Count { get; } = 0;


			public bool IsReadOnly { get; } = true;


			public IEnumerator<T> GetEnumerator()
			{
				return EMPTY_ENUMERATOR;
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			public int IndexOf(T item)
			{
				return -1;
			}

			public void Insert(int index, T item)
			{
				throw new NotSupportedException();
			}

			public void RemoveAt(int index)
			{
				throw new NotSupportedException();
			}

			public void Add(T item)
			{
				throw new NotSupportedException();
			}

			public void Clear()
			{
				throw new NotSupportedException();
			}

			public bool Contains(T item)
			{
				return false;
			}

			public void CopyTo(T[] array, int arrayIndex)
			{
				if (array == null)
				{
					throw new ArgumentNullException("array");
				}
				if (arrayIndex >= array.Length)
				{
					throw new ArgumentOutOfRangeException("arrayIndex");
				}
			}

			public bool Remove(T item)
			{
				throw new NotSupportedException();
			}
		}

		public static IReadOnlyList<T> EmptyReadOnly<T>()
		{
			return StubbedListImpl<T>.INSTANCE;
		}
	}
	public static class PlayerObjectExtensions
	{
		private const string FUSION_PLAYER_REP_NAME = "[RigManager (FUSION PlayerRep)]";

		private static readonly HashSet<Avatar> _reusableUniqueAvatarSet = new HashSet<Avatar>(64);

		public static IEnumerable<RigManager> GetRemotePlayers()
		{
			return ((IEnumerable<RigManager>)Object.FindObjectsOfType<RigManager>()).Where((RigManager rg) => ((Object)((Component)rg).gameObject).name == "[RigManager (FUSION PlayerRep)]");
		}

		public static IEnumerable<RigManager> GetAllPlayers()
		{
			yield return Player.rigManager;
			foreach (RigManager remotePlayer in GetRemotePlayers())
			{
				yield return remotePlayer;
			}
		}

		public static RigManager? GetRigManager(this Avatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return null;
			}
			if ((Object)(object)((Component)avatar).transform.parent == (Object)null)
			{
				return null;
			}
			return ((Component)((Component)avatar).transform.parent).GetComponent<RigManager>();
		}

		public static Avatar[] GetAllUniqueActiveAvatarPrefabs()
		{
			lock (_reusableUniqueAvatarSet)
			{
				_reusableUniqueAvatarSet.Clear();
				IEnumerable<Avatar> source = from player in GetAllPlayers()
					where (Object)(object)player.avatar != (Object)null
					select player.avatar.GetOriginalPrefab() into avatar
					where (Object)(object)avatar != (Object)null && _reusableUniqueAvatarSet.Add(avatar)
					select avatar;
				return source.ToArray();
			}
		}

		public static IEnumerable<Avatar> GetAllActiveAvatars()
		{
			return from player in GetAllPlayers()
				where (Object)(object)player.avatar != (Object)null
				select player.avatar;
		}

		public static Player_Health? GetHealth(this Avatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return null;
			}
			RigManager rigManager = avatar.GetRigManager();
			if ((Object)(object)rigManager == (Object)null)
			{
				return null;
			}
			if ((Object)(object)rigManager.health == (Object)null)
			{
				return null;
			}
			return ((Il2CppObjectBase)rigManager.health).Cast<Player_Health>();
		}

		public static Avatar? GetAvatar(this Player_Health health)
		{
			if ((Object)(object)((Health)health)._rigManager == (Object)null)
			{
				return null;
			}
			return ((Health)health)._rigManager.avatar;
		}
	}
	public static class AvatarStatCalculationExtension
	{
		public struct AvatarMasses
		{
			public float massTotal;

			public float massPelvis;

			public float massChest;

			public float massArm;

			public float massLeg;

			public float massBody;

			public float massHead;

			public override string ToString()
			{
				return $"Masses[Total={massTotal}kg, [Head={massHead}kg, Chest={massChest}kg, Pelvis={massPelvis}kg, One Arm={massArm}kg, One Leg={massLeg}]]";
			}
		}

		public struct AvatarStats
		{
			public float agility;

			public float speed;

			public float strengthUpper;

			public float strengthLower;

			[Obsolete("This value is computed lazily; it is very likely wrong. It is strongly advised that you do NOT use this.")]
			public float strengthGrip;

			public float vitality;

			public float intelligence;

			public override string ToString()
			{
				return $"Stats[Agility={agility}Ns, Speed={speed}m/s, Lower Strength={strengthLower}, Upper Strength={strengthUpper}, Grip Strength (Secret)={strengthGrip}, Vitality={vitality}, Intelligence={intelligence}]";
			}
		}

		public struct AvatarComputationProperties
		{
			public float eyeHeight;

			public float t1HeightPercent;

			public Vector3 sternumOffset;

			public Vector3 sternumOffsetPercent;

			public Vector3 hipOffset;

			public Vector3 hipOffsetPercent;

			public Vector3 hipsPosition;

			public float sacrumHeightPercent;

			public float upperArmLength;

			public float upperLegLength;

			public float lowerArmLength;

			public float lowerLegLength;

			public float chestToShoulderPerc;

			[Obsolete("This value is computed lazily; it is very likely wrong. It is strongly advised that you do NOT use this.")]
			public float handSizeMult;
		}

		private const float PI = (float)Math.PI;

		private static Vector3 GetPositionBetween(Animator animator, HumanBodyBones first, HumanBodyBones second)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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)
			return Vector3.LerpUnclamped(animator.GetBoneTransform(first).position, animator.GetBoneTransform(second).position, 0.5f);
		}

		public static Vector3 EyePosition(this Avatar avatar)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)avatar.eyeCenterOverride))
			{
				return avatar.eyeCenterOverride.position;
			}
			return GetPositionBetween(avatar.animator, (HumanBodyBones)21, (HumanBodyBones)22);
		}

		public static float GetEyeHeight(this Avatar avatar)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return avatar.EyePosition().y - ((Component)avatar).transform.position.y;
		}

		public static void ComputeAllStats(this Avatar avatar, out AvatarMasses mass, out AvatarStats stats)
		{
			mass = avatar.ComputeMass(out var additionalInfo);
			stats = avatar.ComputeBaseStats(mass, additionalInfo);
		}

		public static AvatarMasses ComputeMass(this Avatar avatar, out AvatarComputationProperties additionalInfo, float normalizeTo82 = 0.5f)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: 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_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0503: Unknown result type (might be due to invalid IL or missing references)
			//IL_0516: Unknown result type (might be due to invalid IL or missing references)
			//IL_0523: Unknown result type (might be due to invalid IL or missing references)
			//IL_0528: Unknown result type (might be due to invalid IL or missing references)
			//IL_052d: Unknown result type (might be due to invalid IL or missing references)
			//IL_055c: Unknown result type (might be due to invalid IL or missing references)
			//IL_055e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Unknown result type (might be due to invalid IL or missing references)
			//IL_0567: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Unknown result type (might be due to invalid IL or missing references)
			//IL_0592: Unknown result type (might be due to invalid IL or missing references)
			//IL_0594: Unknown result type (might be due to invalid IL or missing references)
			//IL_059b: Unknown result type (might be due to invalid IL or missing references)
			//IL_059d: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)avatar).transform;
			Animator animator = avatar.animator;
			Quaternion val = Quaternion.Inverse(transform.rotation);
			Vector3 position = animator.GetBoneTransform((HumanBodyBones)9).position;
			float eyeHeight = avatar.GetEyeHeight();
			Vector3 position2 = animator.GetBoneTransform((HumanBodyBones)0).position;
			float num = (position.y - transform.position.y) / eyeHeight;
			Vector3 val2 = val * (GetPositionBetween(animator, (HumanBodyBones)13, (HumanBodyBones)14) - position);
			Vector3 val3 = val2 / eyeHeight;
			Vector3 val4 = val * (GetPositionBetween(animator, (HumanBodyBones)1, (HumanBodyBones)2) - position2);
			Vector3 val5 = val4 / eyeHeight;
			float num2 = (position2.y - transform.position.y) / eyeHeight;
			Vector3 val6 = animator.GetBoneTransform((HumanBodyBones)14).position - animator.GetBoneTransform((HumanBodyBones)8).position;
			float chestToShoulderPerc = (val * val6).x / eyeHeight;
			Vector3 val7 = val * (animator.GetBoneTransform((HumanBodyBones)16).position - animator.GetBoneTransform((HumanBodyBones)14).position);
			Vector3 val8 = val * (avatar.wristRt.position - animator.GetBoneTransform((HumanBodyBones)16).position);
			Vector3 val9 = val * (animator.GetBoneTransform((HumanBodyBones)4).position - animator.GetBoneTransform((HumanBodyBones)2).position);
			Vector3 val10 = val * (animator.GetBoneTransform((HumanBodyBones)6).position - animator.GetBoneTransform((HumanBodyBones)4).position);
			float magnitude = ((Vector3)(ref val7)).magnitude;
			float magnitude2 = ((Vector3)(ref val9)).magnitude;
			float magnitude3 = ((Vector3)(ref val8)).magnitude;
			float magnitude4 = ((Vector3)(ref val10)).magnitude;
			float num3 = (val3.y + num - (val5.y + num2)) * eyeHeight * 0.55f;
			float num4 = (avatar.ChestEllipseZ + avatar.ChestEllipseNegZ + avatar.SternumEllipseZ + avatar.SternumEllipseNegZ + avatar.bulgeBreast.apexZ + avatar.bulgeUpperBack.apexZ) * 0.5f * eyeHeight * (avatar.ChestEllipseX + avatar.ChestEllipseX) * eyeHeight * num3 * 0.7854f * 1000f;
			float num5 = (avatar.WaistEllipseZ + avatar.WaistEllipseNegZ + avatar.HipsEllipseZ + avatar.HipsEllipseNegZ + avatar.bulgeButt.apexZ + avatar.bulgeAbdomen.apexZ + avatar.bulgeLowerBack.apexZ) * 0.5f * eyeHeight * (eyeHeight * avatar.HipsEllipseX + avatar.WaistEllipseX) * num3 * 0.7854f * 1000f;
			float num6 = Mathf.Pow(AverageTotalRadius(avatar.elbowEllipse, avatar.forearmEllipse, avatar.wristEllipse) * eyeHeight, 2f) * (float)Math.PI * magnitude3 * 1000f;
			float num7 = Mathf.Pow(AverageTotalRadius(avatar.upperarmEllipse, avatar.elbowEllipse) * eyeHeight, 2f);
			float num8 = (num6 + num7 * (float)Math.PI * magnitude * 1000f) * 1.11538f;
			float num9 = Mathf.Pow(AverageTotalRadius(avatar.kneeEllipse, avatar.calfEllipse, avatar.ankleEllipse) * eyeHeight, 2f) * (float)Math.PI * magnitude4 * 1000f;
			float num10 = num9 + Mathf.Pow(AverageTotalRadius(avatar.thighUpperEllipse, avatar.kneeEllipse) * eyeHeight, 2f) * (float)Math.PI * magnitude2 * 1100f;
			float num11 = (num8 + num8 + (num5 + num4) + (num10 + num10)) * 1.0764263f;
			float num12 = Mathf.Clamp((avatar.ChestEllipseNegZ + avatar.ChestEllipseZ) / (avatar.WaistEllipseNegZ + avatar.WaistEllipseZ) - 0.1f, 0.7f, 1f);
			float num13 = ((82f - num11) * Mathf.Clamp01(normalizeTo82) + num11) * num12 / num11;
			float massTotal = num11 * num13;
			AvatarMasses avatarMasses = default(AvatarMasses);
			avatarMasses.massPelvis = num5 * num13;
			avatarMasses.massTotal = massTotal;
			avatarMasses.massChest = num4 * num13;
			avatarMasses.massArm = num13 * num8;
			avatarMasses.massLeg = num13 * num10;
			AvatarMasses result = avatarMasses;
			result.massBody = result.massPelvis + result.massChest + result.massArm + result.massArm + result.massLeg + result.massLeg;
			result.massHead = result.massTotal - result.massBody;
			Vector3 val11 = animator.GetBoneTransform((HumanBodyBones)39).position - animator.GetBoneTransform((HumanBodyBones)42).position;
			float magnitude5 = ((Vector3)(ref val11)).magnitude;
			val11 = animator.GetBoneTransform((HumanBodyBones)42).position - animator.GetBoneTransform((HumanBodyBones)43).position;
			float magnitude6 = ((Vector3)(ref val11)).magnitude;
			val11 = animator.GetBoneTransform((HumanBodyBones)43).position - animator.GetBoneTransform((HumanBodyBones)44).position;
			float magnitude7 = ((Vector3)(ref val11)).magnitude;
			float handSizeMult = (magnitude5 + magnitude6 + magnitude7) / 0.12762f;
			additionalInfo = new AvatarComputationProperties
			{
				eyeHeight = eyeHeight,
				hipOffset = val4,
				hipOffsetPercent = val5,
				hipsPosition = position2,
				lowerArmLength = magnitude3,
				lowerLegLength = magnitude4,
				sacrumHeightPercent = num2,
				sternumOffset = val2,
				sternumOffsetPercent = val3,
				upperArmLength = magnitude,
				upperLegLength = magnitude2,
				t1HeightPercent = num,
				chestToShoulderPerc = chestToShoulderPerc,
				handSizeMult = handSizeMult
			};
			return result;
		}

		public static AvatarStats ComputeBaseStats(this Avatar avatar, AvatarMasses masses, AvatarComputationProperties additionalInfo)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: 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_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			float eyeHeight = additionalInfo.eyeHeight;
			float num = avatar.ForeheadEllipseX / 0.044f;
			float num2 = eyeHeight / 1.638f;
			float num3 = masses.massTotal / 75f;
			float num4 = (additionalInfo.chestToShoulderPerc * 10.354f + avatar.ChestEllipseX * 10.354f) * 0.5f;
			float num5 = (additionalInfo.sternumOffsetPercent.y + additionalInfo.t1HeightPercent - (additionalInfo.hipOffsetPercent.y + additionalInfo.sacrumHeightPercent)) / 0.31253165f;
			float num6 = AverageTotalRadius(avatar.upperarmEllipse, avatar.elbowEllipse) * (float)Math.PI;
			num6 /= 0.10681416f;
			if ((double)num6 < 1.0)
			{
				num6 += (1f - num6) * 0.6f;
			}
			float num7 = AverageTotalRadius(avatar.forearmEllipse, avatar.wristEllipse) * (float)Math.PI;
			num7 /= 0.081681415f;
			if ((double)num7 < 1.0)
			{
				num7 += (1f - num7) * 0.6f;
			}
			float num8 = AverageTotalRadius(avatar.thighUpperEllipse, avatar.kneeEllipse) * (float)Math.PI;
			num8 /= 0.14215706f;
			float num9 = additionalInfo.lowerLegLength / additionalInfo.eyeHeight;
			float num10 = additionalInfo.upperLegLength / additionalInfo.eyeHeight;
			float num11 = additionalInfo.lowerArmLength / additionalInfo.eyeHeight;
			float num12 = additionalInfo.upperArmLength / additionalInfo.eyeHeight;
			float num13 = (num9 + num10) / 0.506831f;
			float num14 = GrandTotalRadius(avatar.calfEllipse, avatar.ankleEllipse);
			float num15 = num7 * num3 * additionalInfo.handSizeMult;
			float num16 = num14 * 0.25f;
			float num17 = (num16 * (float)Math.PI / 0.09738937f + num8) * 0.5f * (num13 * num13) * num2 / num3;
			if ((double)num17 < 1.0)
			{
				num17 = Mathf.Pow(num17, 1f / 3f);
			}
			float num18 = Mathf.Clamp01((Mathf.Abs(num13 - 1f) - 1f) * -1f);
			float num19 = Mathf.Sqrt(Mathf.Abs(num));
			float num20 = Mathf.Clamp01((Mathf.Abs(num19 - 1f) - 1f) * -1f);
			AvatarStats result = default(AvatarStats);
			result.speed = num17 * num2;
			result.vitality = num5 * num3 * num2;
			result.intelligence = num;
			result.agility = Mathf.Max((num20 + 1f) * 0.5f, 0.5f) * Mathf.Max(num18, 0.5f);
			result.strengthUpper = num4 * (num3 * (num6 * (num2 / ((num11 + num12) / 0.317f))));
			result.strengthLower = num8 * num3 * num2 / num13;
			result.strengthGrip = num15 * num2;
			return result;
		}

		private static float RadiusTotal(SoftEllipse ellipse)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return ellipse.XRadius + ellipse.ZRadius;
		}

		private static float AverageTotalRadius(params SoftEllipse[] ellipses)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			for (int i = 0; i < ellipses.Length; i++)
			{
				num += RadiusTotal(ellipses[i]);
			}
			return num / (float)(ellipses.Length << 1);
		}

		private static float GrandTotalRadius(params SoftEllipse[] ellipses)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			for (int i = 0; i < ellipses.Length; i++)
			{
				num += RadiusTotal(ellipses[i]);
			}
			return num;
		}
	}
	public static class SoundPlayerSystem
	{
		public static GameObject PlaySound(Transform on, AudioClip sound, float volume = 1f, float pitch = 1f, bool playAs2D = false, SoundFlags flags = SoundFlags.FollowEmitter | SoundFlags.RealtimePitchShift, AudioMixerGroup? mixer = null)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			Log.Trace("Playing sound: " + ((Object)sound).name + "...");
			GameObject val = new GameObject();
			if ((Object)(object)on == (Object)null)
			{
				on = ((Component)Camera.main).gameObject.transform;
			}
			val.transform.parent = on;
			val.transform.localPosition = Vector3.zero;
			bool flag = flags.HasFlag(SoundFlags.RealtimePitchShift);
			bool flag2 = flag || flags.HasFlag(SoundFlags.PitchShift);
			bool flag3 = flags.HasFlag(SoundFlags.FollowEmitter);
			float num = pitch;
			if (flag2)
			{
				num *= Time.timeScale;
			}
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.outputAudioMixerGroup = (AudioMixerGroup)(Object.op_Implicit((Object)(object)mixer) ? ((object)mixer) : ((object)Audio.SFXMixer));
			val2.volume = volume;
			val2.pitch = num;
			val2.loop = false;
			val2.playOnAwake = false;
			val2.clip = sound;
			SetupDefaultNearbyCurves(val2, playAs2D);
			val2.Play();
			if (!flag && !flag3)
			{
				Object.Destroy((Object)(object)val, sound.length + 0.2f);
			}
			else
			{
				RealtimeSoundDriver.StartDriving(val2, flag3, flag);
			}
			((Object)val).name = ((Object)sound).name;
			return val;
		}

		public static GameObject PlaySound(Transform on, PlayableSoundData sound, AudioSource? template)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			Log.Trace("Playing sound: " + ((Object)sound.sound).name + "...");
			GameObject val = new GameObject();
			if ((Object)(object)on == (Object)null)
			{
				on = ((Component)Camera.main).gameObject.transform;
			}
			val.transform.parent = on;
			val.transform.localPosition = Vector3.zero;
			SoundFlags playTechnique = sound.playTechnique;
			AudioMixerGroup mixer = sound.mixer;
			bool flag = playTechnique.HasFlag(SoundFlags.RealtimePitchShift);
			bool flag2 = flag || playTechnique.HasFlag(SoundFlags.PitchShift);
			bool flag3 = playTechnique.HasFlag(SoundFlags.FollowEmitter);
			float num = sound.pitch;
			if (flag2)
			{
				num *= Time.timeScale;
			}
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.outputAudioMixerGroup = (Object.op_Implicit((Object)(object)mixer) ? mixer : Audio.SFXMixer);
			val2.volume = sound.volume;
			val2.pitch = num;
			val2.loop = false;
			val2.playOnAwake = false;
			val2.clip = sound.sound;
			if ((Object)(object)template == (Object)null || ((Object)template).name == "Nearby Spatial Source" || ((Object)template).name == "Global Source")
			{
				SetupDefaultNearbyCurves(val2, isPlayingAs2D: false);
			}
			else
			{
				CopyCurves(val2, template);
			}
			val2.Play();
			if (!flag && !flag3 && !val2.loop)
			{
				Object.Destroy((Object)(object)val, sound.sound.length + 0.2f);
			}
			else
			{
				RealtimeSoundDriver.StartDriving(val2, flag3, flag);
			}
			((Object)val).name = ((Object)val2.clip).name;
			return val;
		}

		private static void SetupDefaultNearbyCurves(AudioSource src, bool isPlayingAs2D)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Expected O, but got Unknown
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Expected O, but got Unknown
			src.rolloffMode = (AudioRolloffMode)2;
			if (!isPlayingAs2D)
			{
				Il2CppStructArray<Keyframe> val = new Il2CppStructArray<Keyframe>(3L);
				((Il2CppArrayBase<Keyframe>)(object)val)[0] = new Keyframe(0.1f, 1f, 0f, 0f, 0.3333333f, 0.3333333f);
				((Il2CppArrayBase<Keyframe>)(object)val)[1] = new Keyframe(0.3540465f, 0.2750549f, -1.329637f, -1.329637f, 0.3333333f, 0.3333333f);
				((Il2CppArrayBase<Keyframe>)(object)val)[2] = new Keyframe(1f, 0f, -0.1762998f, -0.1762998f, 0.3204496f, 0.3333333f);
				Il2CppStructArray<Keyframe> val2 = new Il2CppStructArray<Keyframe>(2L);
				((Il2CppArrayBase<Keyframe>)(object)val2)[0] = new Keyframe(0f, 0.5f, -0.3094383f, -0.3094383f, 0.4783377f, 0f);
				((Il2CppArrayBase<Keyframe>)(object)val2)[1] = new Keyframe(1f, 0f, 0f, 0f, 0.3333333f, 0.3333333f);
				Il2CppStructArray<Keyframe> val3 = new Il2CppStructArray<Keyframe>(4L);
				((Il2CppArrayBase<Keyframe>)(object)val3)[0] = new Keyframe(0f, 0f, 0f, 0f, 0.3333333f, 0.3333333f);
				((Il2CppArrayBase<Keyframe>)(object)val3)[1] = new Keyframe(0.1896423f, 0.8151474f, 1.837119f, 1.837119f, 0.07648899f, 0.07007767f);
				((Il2CppArrayBase<Keyframe>)(object)val3)[2] = new Keyframe(0.4214395f, 0.9818153f, 0.1665137f, 0.1665137f, 0.6917831f, 0f);
				((Il2CppArrayBase<Keyframe>)(object)val3)[3] = new Keyframe(1f, 1f, 0f, 0f, 0.3333333f, 0.3333333f);
				Il2CppStructArray<Keyframe> val4 = new Il2CppStructArray<Keyframe>(3L);
				((Il2CppArrayBase<Keyframe>)(object)val4)[0] = new Keyframe(0f, 0f, 0f, 0f, 0.3333333f, 0.3333333f);
				((Il2CppArrayBase<Keyframe>)(object)val4)[1] = new Keyframe(0.3287202f, 0.1654926f, 1.535669f, 1.535669f, 0.3333333f, 0.3333333f);
				((Il2CppArrayBase<Keyframe>)(object)val4)[2] = new Keyframe(0.4605339f, 1f, 0.04093663f, 0.04093663f, 0.1604803f, 0f);
				src.rolloffMode = (AudioRolloffMode)2;
				src.SetCustomCurve((AudioSourceCurveType)0, new AnimationCurve(val));
				src.SetCustomCurve((AudioSourceCurveType)3, new AnimationCurve(val2));
				src.SetCustomCurve((AudioSourceCurveType)1, new AnimationCurve(val3));
				src.SetCustomCurve((AudioSourceCurveType)2, new AnimationCurve(val4));
			}
			else
			{
				src.spatialBlend = 0f;
				src.reverbZoneMix = 0f;
			}
			src.maxDistance = 7f;
		}

		private static void CopyCurves(AudioSource destination, AudioSource template)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			destination.rolloffMode = (AudioRolloffMode)2;
			destination.priority = template.priority;
			destination.bypassEffects = template.bypassEffects;
			destination.bypassListenerEffects = template.bypassListenerEffects;
			destination.bypassReverbZones = template.bypassReverbZones;
			destination.maxDistance = template.maxDistance;
			destination.minDistance = template.minDistance;
			destination.rolloffMode = template.rolloffMode;
			destination.velocityUpdateMode = template.velocityUpdateMode;
			destination.loop = template.loop;
			destination.SetCustomCurve((AudioSourceCurveType)0, destination.GetCustomCurve((AudioSourceCurveType)0));
			destination.SetCustomCurve((AudioSourceCurveType)3, destination.GetCustomCurve((AudioSourceCurveType)3));
			destination.SetCustomCurve((AudioSourceCurveType)1, destination.GetCustomCurve((AudioSourceCurveType)1));
			destination.SetCustomCurve((AudioSourceCurveType)2, destination.GetCustomCurve((AudioSourceCurveType)2));
		}
	}
	public sealed class ReadOnlyHashSet<T> : ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable
	{
		private readonly HashSet<T> _set;

		public int Count { get; }

		public bool IsReadOnly { get; } = true;


		public ReadOnlyHashSet()
		{
			_set = new HashSet<T>();
			Count = 0;
		}

		public ReadOnlyHashSet(IEnumerable<T> set)
		{
			_set = new HashSet<T>(set);
			Count = _set.Count;
		}

		public bool ContainsAny(T[] of)
		{
			for (int i = 0; i < of.Length; i++)
			{
				if (Contains(of[i]))
				{
					return true;
				}
			}
			return false;
		}

		public bool Add(T item)
		{
			throw new NotSupportedException();
		}

		public void UnionWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		public void IntersectWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		public void ExceptWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		public void SymmetricExceptWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		public bool IsSubsetOf(IEnumerable<T> other)
		{
			return _set.IsSubsetOf(other);
		}

		public bool IsSupersetOf(IEnumerable<T> other)
		{
			return _set.IsSupersetOf(other);
		}

		public bool IsProperSupersetOf(IEnumerable<T> other)
		{
			return _set.IsProperSupersetOf(other);
		}

		public bool IsProperSubsetOf(IEnumerable<T> other)
		{
			return _set.IsProperSubsetOf(other);
		}

		public bool Overlaps(IEnumerable<T> other)
		{
			return _set.Overlaps(other);
		}

		public bool SetEquals(IEnumerable<T> other)
		{
			return _set.SetEquals(other);
		}

		void ICollection<T>.Add(T item)
		{
			throw new NotSupportedException();
		}

		public void Clear()
		{
			throw new NotSupportedException();
		}

		public bool Contains(T item)
		{
			return _set.Contains(item);
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			_set.CopyTo(array, arrayIndex);
		}

		public bool Remove(T item)
		{
			throw new NotSupportedException();
		}

		public IEnumerator<T> GetEnumerator()
		{
			return _set.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	public static class SoundBlockNameSanitizer
	{
		private static readonly char[] SEMICOLON = new char[1] { ';' };

		public static readonly Regex SOUND_REGEX = new Regex("[a-z0-9_\\-\\.]+(?:(?:\\:)[a-z0-9_\\-\\.]+)?");

		public static bool IsSane(string unfilteredSingle)
		{
			Match match = SOUND_REGEX.Match(unfilteredSingle);
			return match.Success && match.Value == unfilteredSingle;
		}

		public static string[] GetSanitizedEventList(string unfiltered)
		{
			if (unfiltered.Length == 0)
			{
				return Array.Empty<string>();
			}
			string[] array = unfiltered.Split(SEMICOLON, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = new string[array.Length];
			int newSize = 0;
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!string.IsNullOrEmpty(text) && text.Length <= 50)
				{
					text = text.ToLower();
					Match match = SOUND_REGEX.Match(text);
					if (match.Success && match.Value == text)
					{
						array2[newSize++] = text;
					}
				}
			}
			Array.Resize(ref array2, newSize);
			return array2;
		}

		public static string[] GetSanitizedEventList(string[] names)
		{
			if (names.Length == 0)
			{
				return Array.Empty<string>();
			}
			string[] array = new string[names.Length];
			int newSize = 0;
			for (int i = 0; i < names.Length; i++)
			{
				string text = names[i].Trim();
				if (!string.IsNullOrEmpty(text) && text.Length <= 50)
				{
					text = text.ToLower();
					Match match = SOUND_REGEX.Match(text);
					if (match.Success && match.Value == text)
					{
						array[newSize++] = text;
					}
				}
			}
			Array.Resize(ref array, newSize);
			return array;
		}

		public static string GetSanitizedEventListJoined(string unfiltered)
		{
			string[] sanitizedEventList = GetSanitizedEventList(unfiltered);
			if (sanitizedEventList.Length == 0)
			{
				return string.Empty;
			}
			if (sanitizedEventList.Length == 1)
			{
				return sanitizedEventList[0];
			}
			return string.Join(";", sanitizedEventList);
		}

		public static void CreateStringAndEnumMix(string unfiltered, out string[] customs, out AudioEventType enums)
		{
			customs = GetSanitizedEventList(unfiltered);
			enums = AudioEventType.Custom;
			CreateStringAndEnumMix(ref customs, ref enums);
		}

		public static void CreateStringAndEnumMix(string[] unfilteredArray, out string[] customs, out AudioEventType enums)
		{
			customs = GetSanitizedEventList(unfilteredArray);
			enums = AudioEventType.Custom;
			CreateStringAndEnumMix(ref customs, ref enums);
		}

		private static void CreateStringAndEnumMix(ref string[] customs, ref AudioEventType enums)
		{
			int newSize = 0;
			for (int i = 0; i < customs.Length; i++)
			{
				int num = AudioEventTypeExt.ALL_FLAGS_EVENT_NAMES.IndexOf(customs[i]);
				if (num < 0)
				{
					customs[newSize++] = customs[i];
				}
				else
				{
					enums |= AudioEventTypeExt.ALL_FLAGS[num];
				}
			}
			Array.Resize(ref customs, newSize);
		}
	}
	public sealed class StatMarshaller
	{
		internal static void Initialize(Harmony harmony)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			Log.Info("Patching SLZ::VRMK::Avatar::ComputeBaseStats...");
			harmony.Patch((MethodBase)QuickGetMethod<Avatar>("ComputeBaseStats"), (HarmonyMethod)null, new HarmonyMethod(QuickGetMethod<StatMarshaller>("ComputeStatsPostfix")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Log.Info("Patching SLZ::VRMK::Avatar::ComputeMass...");
			harmony.Patch((MethodBase)QuickGetMethod<Avatar>("ComputeMass"), (HarmonyMethod)null, new HarmonyMethod(QuickGetMethod<StatMarshaller>("ComputeMassPostfix")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Log.Info("Patching SLZ::Rig::RemapRig::JumpCharge...");
			harmony.Patch((MethodBase)QuickGetMethod<RemapRig>("JumpCharge"), (HarmonyMethod)null, new HarmonyMethod(QuickGetMethod<StatMarshaller>("JumpChargePostfix")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Log.Info("Patches performed.");
		}

		private static void ComputeStatsPostfix(Avatar __instance)
		{
			ApplyStats(__instance);
		}

		private static void ComputeMassPostfix(Avatar __instance)
		{
			ApplyStats(__instance);
		}

		private static void JumpChargePostfix(bool chargeInput = true)
		{
			Avatar currentAvatar = Player.GetCurrentAvatar();
			OnJump(currentAvatar, chargeInput);
		}

		private static void OnJump(Avatar avatar, bool isJumpButtonDown)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			AvatarStatDriver component = ((Component)avatar).gameObject.GetComponent<AvatarStatDriver>();
			if (!((Object)(object)component == (Object)null))
			{
				JumpTracker jumpTracker = ((Component)avatar).GetComponent<JumpTracker>();
				if ((Object)(object)jumpTracker == (Object)null)
				{
					jumpTracker = ((Component)avatar).gameObject.AddComponent<JumpTracker>();
				}
				PhysicsRig physicsRig = Player.GetPhysicsRig();
				PhysGrounder physG = physicsRig.physG;
				jumpTracker.MarkPlayerOnGround(physG.isGrounded);
				if (jumpTracker.TryJump(isJumpButtonDown))
				{
					physicsRig.torso.rbPelvis.AddForce(Vector3.up * component.extraJumpVerticalVelocity, (ForceMode)2);
				}
			}
		}

		private static void ApplyStats(Avatar avatar)
		{
			AvatarStatDriver component = ((Component)avatar).gameObject.GetComponent<AvatarStatDriver>();
			if (!((Object)(object)component == (Object)null))
			{
				Log.Debug("Enforcing that stats are applied to the desired avatar.");
				avatar._agility = component.EffectiveAgility;
				avatar._speed = component.EffectiveSpeed;
				avatar._strengthUpper = component.EffectiveUpperStrength;
				avatar._strengthLower = component.EffectiveLowerStrength;
				avatar._vitality = component.EffectiveVitality;
				avatar._intelligence = component.EffectiveIntelligence;
				avatar._massChest = component.EffectiveChestMass;
				avatar._massPelvis = component.EffectivePelvisMass;
				avatar._massLeg = component.EffectiveLegMass;
				avatar._massArm = component.EffectiveArmMass;
				avatar._massHead = component.EffectiveHeadMass;
				avatar._massTotal = component.EffectiveTotalMass;
				Log.Debug("Stats and masses have been applied to " + ((Object)avatar).name);
			}
		}

		private static MethodInfo QuickGetMethod<T>(string name)
		{
			return typeof(T).GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		}
	}
	public static class Tools
	{
		private static readonly CultureInfo PERCENT_CULTURE;

		static Tools()
		{
			PERCENT_CULTURE = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
			PERCENT_CULTURE.NumberFormat.PercentPositivePattern = 1;
		}

		public static string FormatPercentage(this float value, int digits = 2)
		{
			string text = $"P{digits}";
			return value.ToString(text, PERCENT_CULTURE);
		}

		public static void ResizeArrayDefault<T>(ref T[] array, int newLength, T fillWith)
		{
			int num = array.Length;
			Array.Resize(ref array, newLength);
			if (num < newLength)
			{
				for (int i = num; i < newLength; i++)
				{
					array[i] = fillWith;
				}
			}
		}
	}
	internal static class XPlat
	{
		public const CompatiblePlatforms META_QUEST = 3;

		public static bool IsQuestie => (int)MelonUtils.CurrentPlatform == 3;
	}
}
namespace AvatarStatExtender.Tools.Assets
{
	public static class AssetLocator
	{
		public static bool IsPrefabAvatar(this Avatar avatar)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			int result;
			if (((Component)avatar).gameObject.scene != SceneManager.GetActiveScene())
			{
				Scene scene = ((Component)avatar).gameObject.scene;
				result = ((!((Scene)(ref scene)).IsValid()) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}

		private static Avatar? BruteForceFindCrateOfAvatar(Avatar avatar)
		{
			if (avatar.IsPrefabAvatar())
			{
				return avatar;
			}
			QuickPrefabIdentifier quickPrefabIdentifier = null;
			QuickPrefabIdentifier component = ((Component)avatar).GetComponent<QuickPrefabIdentifier>();
			if (component != null && (Object)(object)component != (Object)null)
			{
				quickPrefabIdentifier = component;
				if ((Object)(object)quickPrefabIdentifier.Prefab != (Object)null)
				{
					return quickPrefabIdentifier.Prefab;
				}
			}
			Log.Trace("Searching the warehouse for the crate of " + ((Object)avatar).name + "...");
			Animator component2 = ((Component)avatar).GetComponent<Animator>();
			AvatarCrate[] array = Il2CppArrayBase<AvatarCrate>.op_Implicit(AssetWarehouse.Instance.GetCrates<AvatarCrate>((ICrateFilter<AvatarCrate>)null).ToArray());
			foreach (AvatarCrate val in array)
			{
				if (!((MarrowAsset)(object)((GameObjectCrate)val).MainGameObject != (MarrowAsset)null))
				{
					continue;
				}
				GameObject asset = ((MarrowAssetT<GameObject>)(object)((GameObjectCrate)val).MainGameObject).Asset;
				if (asset == null || !((Object)(object)asset != (Object)null))
				{
					continue;
				}
				Animator component3 = asset.GetComponent<Animator>();
				if (component3 != null && (Object)(object)component3 != (Object)null && (Object)(object)component3.avatar == (Object)(object)component2.avatar)
				{
					Log.Trace("Found the prefab! I'll cache it now for this clone.");
					Avatar component4 = asset.GetComponent<Avatar>();
					if ((Object)(object)quickPrefabIdentifier == (Object)null)
					{
						quickPrefabIdentifier = ((Component)avatar).gameObject.AddComponent<QuickPrefabIdentifier>();
					}
					quickPrefabIdentifier.Prefab = component4;
					return component4;
				}
			}
			Log.Trace("No luck, chief.");
			return null;
		}

		public static Avatar? GetOriginalPrefab(this Avatar avatar)
		{
			return BruteForceFindCrateOfAvatar(avatar);
		}
	}
}
namespace AvatarStatExtender.Components
{
	[RegisterTypeInIl2Cpp]
	public sealed class JumpTracker : MonoBehaviour
	{
		private bool _hasPressedJumpButton = false;

		private bool _hasAlreadyJumped = false;

		private bool _isOnGround = false;

		public JumpTracker(IntPtr @this)
			: base(@this)
		{
		}

		public void MarkPlayerOnGround(bool isGrounded)
		{
			_isOnGround = isGrounded;
		}

		public bool TryJump(bool isJumpButtonPressed)
		{
			if (isJumpButtonPressed)
			{
				_hasPressedJumpButton = true;
				if (_isOnGround)
				{
					_hasAlreadyJumped = false;
				}
				return false;
			}
			bool result = false;
			if (_isOnGround && _hasPressedJumpButton && !_hasAlreadyJumped)
			{
				_hasAlreadyJumped = true;
				result = true;
			}
			else if (_isOnGround && !_hasPressedJumpButton)
			{
				_hasAlreadyJumped = false;
			}
			_hasPressedJumpButton = false;
			return result;
		}
	}
	[RegisterTypeInIl2Cpp]
	internal sealed class QuickPrefabIdentifier : MonoBehaviour
	{
		public Avatar? Prefab { get; set; }

		public QuickPrefabIdentifier(IntPtr @this)
			: base(@this)
		{
		}
	}
	[RegisterTypeInIl2Cpp]
	public sealed class RealtimeSoundDriver : MonoBehaviour
	{
		[AllowNull]
		private AudioSource _src;

		private float _originalPitch = 1f;

		public bool pitchShiftInRealtime = false;

		public bool followParent = false;

		private Vector3? _globalOffset;

		public Vector3 LocalOffset { get; set; }

		public Vector3 GlobalOffset
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return _globalOffset.GetValueOrDefault();
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				if (value == Vector3.zero)
				{
					_globalOffset = null;
				}
				else
				{
					_globalOffset = value;
				}
			}
		}

		public RealtimeSoundDriver(IntPtr @this)
			: base(@this)
		{
		}

		public static void StartDriving(AudioSource sound, bool followParent, bool pitchShiftInRealtime)
		{
			RealtimeSoundDriver realtimeSoundDriver = ((Component)sound).gameObject.AddComponent<RealtimeSoundDriver>();
			realtimeSoundDriver.pitchShiftInRealtime = pitchShiftInRealtime;
			realtimeSoundDriver.followParent = followParent;
		}

		private void Start()
		{
			_src = ((Component)this).GetComponent<AudioSource>();
			_originalPitch = _src.pitch;
		}

		private void Update()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_src == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			if (!_src.isPlaying)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			if (followParent)
			{
				((Component)this).transform.localPosition = LocalOffset;
				if (_globalOffset.HasValue)
				{
					if ((Object)(object)((Component)this).transform.parent != (Object)null)
					{
						Vector3 val = Vector4.op_Implicit(((Component)this).transform.parent.localToWorldMatrix * Vector4.op_Implicit(_globalOffset.Value));
						Transform transform = ((Component)this).transform;
						transform.localPosition += val;
					}
					else
					{
						Transform transform2 = ((Component)this).transform;
						transform2.localPosition += _globalOffset.Value;
					}
				}
			}
			if (pitchShiftInRealtime)
			{
				_src.pitch = _originalPitch * Time.timeScale;
			}
		}
	}
}
namespace AvatarStatExtender.Data
{
	internal static class AudioEntries
	{
		public static IEnumerable<AudioEntry> EntriesFromContainer(this AvatarExtendedAudioContainer container)
		{
			if ((Object)(object)container == (Object)null)
			{
				throw new ArgumentNullException("container", "The audio container cannot be null.");
			}
			container.EnsureSymmetry();
			int length = container.names.Length;
			for (int index = 0; index < length; index++)
			{
				yield return container.EntryFromContainer(index, skipSymmetry: true);
			}
		}

		public static bool TryRemoveEntry(this AvatarExtendedAudioContainer container, AudioEntry entry)
		{
			if ((Object)(object)container == (Object)null)
			{
				throw new ArgumentNullException("container", "The audio container cannot be null.");
			}
			if (entry == null)
			{
				throw new ArgumentNullException("entry", "The audio entry cannot be null.");
			}
			int num = container.Entries.IndexOf(entry);
			if (num >= 0)
			{
				container.Entries.RemoveAt(num);
				container.OverwriteFromEntries(container.Entries);
				return true;
			}
			return false;
		}

		public static bool TryRemoveEntryAt(this AvatarExtendedAudioContainer container, int index)
		{
			if ((Object)(object)container == (Object)null)
			{
				throw new ArgumentNullException("container", "The audio container cannot be null.");
			}
			if (index < 0 || index >= container.Entries.Count)
			{
				return false;
			}
			container.Entries.RemoveAt(index);
			container.OverwriteFromEntries(container.Entries);
			return true;
		}

		public static AudioEntry EntryFromContainer(this AvatarExtendedAudioContainer container, int index, bool skipSymmetry = false)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)container == (Object)null)
			{
				throw new ArgumentNullException("container", "The audio container cannot be null.");
			}
			if (!skipSymmetry)
			{
				container.EnsureSymmetry();
			}
			string name = container.names[index] ?? string.Empty;
			SerializableAudioArray serializableAudioArray = container.sounds[index];
			if (serializableAudioArray == null)
			{
				serializableAudioArray = new SerializableAudioArray();
				container.sounds[index] = serializableAudioArray;
			}
			AudioClip[] source = serializableAudioArray.Clips.ToArray();
			AudioPlayType playType = container.playTypes[index];
			AudioEventType eventType = container.eventTypes[index];
			string customPlayType = container.customPlayTypes[index];
			string customEventTypes = container.customEventTypes[index];
			Vector2 pitchRange = container.pitchRanges[index];
			float volume = container.volumes[index];
			AudioMixerTarget mixerTarget = container.mixers[index];
			SoundFlags soundFlags = container.soundFlags[index];
			AudioSource overrideTemplateAudioSrc = container.templateSources[index];
			return new AudioEntry(name, playType, customPlayType, eventType, customEventTypes, source.ToList(), pitchRange, volume, mixerTarget, soundFlags, overrideTemplateAudioSrc);
		}

		public static void OverwriteFromEntries(this AvatarExtendedAudioContainer container, IEnumerable<AudioEntry> entriesEnumerable)
		{
			if ((Object)(object)container == (Object)null)
			{
				throw new ArgumentNullException("container", "The audio container cannot be null.");
			}
			AudioEntry[] array = entriesEnumerable.ToArray();
			int num = array.Length;
			Array.Resize(ref container.names, num);
			Array.Resize(ref container.sounds.children, num);
			Array.Resize(ref container.playTypes, num);
			Array.Resize(ref container.eventTypes, num);
			Array.Resize(ref container.customPlayTypes, num);
			Array.Resize(ref container.customEventTypes, num);
			Array.Resize(ref container.pitchRanges, num);
			Array.Resize(ref container.volumes, num);
			Array.Resize(ref container.mixers, num);
			Array.Resize(ref container.soundFlags, num);
			Array.Resize(ref container.templateSources, num);
			for (int i = 0; i < num; i++)
			{
				container.OverwriteFromEntry(array[i], i, skipSymmetry: true);
			}
		}

		public static void OverwriteFromEntry(this AvatarExtendedAudioContainer container, AudioEntry entry, int index, bool skipSymmetry = false)
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)container == (Object)null)
			{
				throw new ArgumentNullException("container", "The audio container cannot be null.");
			}
			if (!skipSymmetry)
			{
				container.EnsureSymmetry();
			}
			if (entry == null)
			{
				throw new InvalidOperationException($"AudioEntry #{index} is null.");
			}
			container.names[index] = entry.Name;
			if (container.sounds[index] == null)
			{
				container.sounds[index] = new SerializableAudioArray();
			}
			container.sounds[index].Clips = entry.Sounds ?? new List<AudioClip>();
			container.playTypes[index] = entry.PlayType;
			container.eventTypes[index] = entry.EventType;
			container.customPlayTypes[index] = entry.CustomPlayType;
			container.customEventTypes[index] = entry.CustomEventTypes;
			container.pitchRanges[index] = entry.PitchRange;
			container.volumes[index] = entry.Volume;
			container.mixers[index] = entry.Mixer;
			container.soundFlags[index] = entry.SoundFlags;
			container.templateSources[index] = entry.OverrideTemplateAudioSource;
		}
	}
	internal class AudioEntry
	{
		private string? _customEventTypes = null;

		public string Name { get; set; } = "New Sound Group";


		public bool UseCustomPlayType => PlayType == AudioPlayType.Custom;

		public AudioPlayType PlayType { get; set; }

		public string? CustomPlayType { get; set; }

		public AudioEventType EventType { get; set; }

		public string? CustomEventTypes
		{
			get
			{
				return _customEventTypes?.ToLower();
			}
			set
			{
				_customEventTypes = value?.ToLower();
			}
		}

		public List<AudioClip> Sounds { get; set; } = new List<AudioClip>();


		public Vector2 PitchRange { get; set; } = new Vector2(1f, 1f);


		public float Volume { get; set; } = 0.5f;


		public AudioMixerTarget Mixer { get; set; } = AudioMixerTarget.SFX;


		public SoundFlags SoundFlags { get; set; } = SoundFlags.FollowEmitter | SoundFlags.RealtimePitchShift;


		public AudioSource? OverrideTemplateAudioSource { get; set; }

		public AudioEntry()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Name = "New Sound Group";
			PlayType = AudioPlayType.Random;
			EventType = AudioEventType.HitBullet;
			Sounds = new List<AudioClip>();
		}

		public AudioEntry(string name, AudioPlayType playType, string? customPlayType, AudioEventType eventType, string? customEventTypes, List<AudioClip> sounds, Vector2 pitchRange, float volume, AudioMixerTarget mixerTarget, SoundFlags soundFlags, AudioSource overrideTemplateAudioSrc)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			Name = name ?? throw new ArgumentNullException("name");
			PlayType = playType;
			CustomPlayType = customPlayType;
			EventType = eventType;
			CustomEventTypes = customEventTypes;
			Sounds = sounds ?? throw new ArgumentNullException("sounds");
			PitchRange = pitchRange;
			Volume = volume;
			Mixer = mixerTarget;
			SoundFlags = soundFlags;
			OverrideTemplateAudioSource = overrideTemplateAudioSrc;
		}
	}
	internal static class AudioCache
	{
		private static readonly ISet<ReadOnlyAudioEntry> EMPTY = new ReadOnlyHashSet<ReadOnlyAudioEntry>();

		private static readonly Dictionary<IntPtr, ISet<ReadOnlyAudioEntry>> _cachePerAvatar = new Dictionary<IntPtr, ISet<ReadOnlyAudioEntry>>();

		private static readonly Dictionary<IntPtr, Dictionary<string, ISet<ReadOnlyAudioEntry>>> _cachePerAvatarByEventName = new Dictionary<IntPtr, Dictionary<string, ISet<ReadOnlyAudioEntry>>>();

		private static readonly Dictionary<IntPtr, Dictionary<AudioEventType, ISet<ReadOnlyAudioEntry>>> _cachePerAvatarByEventEnum = new Dictionary<IntPtr, Dictionary<AudioEventType, ISet<ReadOnlyAudioEntry>>>();

		public static ISet<ReadOnlyAudioEntry> GetAllSoundsOfAvatar(Avatar avatar)
		{
			Avatar originalPrefab = avatar.GetOriginalPrefab();
			if ((Object)(object)originalPrefab == (Object)null)
			{
				Log.Error("Failed to find original prefab for avatar " + ((Object)avatar).name + " when trying to collect all sounds. An empty set will be returned.");
				return EMPTY;
			}
			return GetAllSoundsOfAvatarPrefab(originalPrefab);
		}

		private static ISet<ReadOnlyAudioEntry> GetAllSoundsOfAvatarPrefab(Avatar originalAvy)
		{
			if (!originalAvy.IsPrefabAvatar())
			{
				throw new ArgumentException("The avatar that called this method was not a prefab (" + ((Object)originalAvy).name + ")");
			}
			IntPtr pointer = ((Il2CppObjectBase)originalAvy).Pointer;
			if (_cachePerAvatar.TryGetValue(pointer, out ISet<ReadOnlyAudioEntry> value))
			{
				return value;
			}
			AvatarExtendedAudioContainer component = ((Component)originalAvy).GetComponent<AvatarExtendedAudioContainer>();
			if (component != null && (Object)(object)component != (Object)null)
			{
				Log.Trace("Avatar has a container for custom sounds...");
				IReadOnlyList<ReadOnlyAudioEntry> entries = component.GetEntries();
				_cachePerAvatar[pointer] = new ReadOnlyHashSet<ReadOnlyAudioEntry>(entries);
				_cachePerAvatarByEventName[pointer] = new Dictionary<string, ISet<ReadOnlyAudioEntry>>();
				_cachePerAvatarByEventEnum[pointer] = new Dictionary<AudioEventType, ISet<ReadOnlyAudioEntry>>();
				foreach (ReadOnlyAudioEntry item in entries)
				{
					Log.Trace("Handling entry: " + item.Name);
					foreach (string resolvedCustomEvent in item.ResolvedCustomEvents)
					{
						if (!_cachePerAvatarByEventName[pointer].TryGetValue(resolvedCustomEvent, out ISet<ReadOnlyAudioEntry> value2))
						{
							value2 = (_cachePerAvatarByEventName[pointer][resolvedCustomEvent] = new HashSet<ReadOnlyAudioEntry>());
						}
						value2.Add(item);
						Log.Trace("Entry " + item.Name + " has registered a custom event: " + resolvedCustomEvent);
					}
					if (item.EventType == AudioEventType.Custom)
					{
						continue;
					}
					Log.Trace("Entry " + item.Name + " declares one or more vanilla event types...");
					for (int i = 0; i < AudioEventTypeExt.ALL_FLAGS.Length; i++)
					{
						AudioEventType audioEventType = AudioEventTypeExt.ALL_FLAGS[i];
						if ((item.EventType & audioEventType) != 0)
						{
							if (!_cachePerAvatarByEventEnum[pointer].TryGetValue(audioEventType, out ISet<ReadOnlyAudioEntry> value3))
							{
								value3 = (_cachePerAvatarByEventEnum[pointer][audioEventType] = new HashSet<ReadOnlyAudioEntry>());
							}
							value3.Add(item);
							Log.Trace($"Entry {item.Name} has registered a vanilla event: {audioEventType}");
						}
					}
				}
				Log.Trace("The cache has been constructed for " + ((Object)component).name);
				return _cachePerAvatar[pointer];
			}
			Log.Trace("Avatar does not have a container for custom sounds.");
			_cachePerAvatarByEventName[pointer] = new Dictionary<string, ISet<ReadOnlyAudioEntry>>();
			_cachePerAvatarByEventEnum[pointer] = new Dictionary<AudioEventType, ISet<ReadOnlyAudioEntry>>();
			_cachePerAvatar[pointer] = EMPTY;
			return EMPTY;
		}

		internal static IEnumerable<ReadOnlyAudioEntry> GetMatchingSoundsFromAvatarSingle(Avatar prefab, string singleCustomEventType)
		{
			IntPtr onAvatar = ((Il2CppObjectBase)prefab).Pointer;
			GetAllSoundsOfAvatarPrefab(prefab);
			if (_cachePerAvatarByEventName.TryGetValue(onAvatar, out Dictionary<string, ISet<ReadOnlyAudioEntry>> entriesLookup))
			{
				if (entriesLookup.TryGetValue(singleCustomEventType, out ISet<ReadOnlyAudioEntry> entries))
				{
					foreach (ReadOnlyAudioEntry item in entries)
					{
						yield return item;
					}
				}
				else
				{
					Log.Trace("Missing sound set in string cache. Skipping.");
				}
			}
			else
			{
				Log.Trace("Missing avatar in string cache. Skipping.");
			}
		}

		internal static IEnumerable<ReadOnlyAudioEntry> GetMatchingSoundsFromAvatarSingle(Avatar prefab, AudioEventType singleEventType)
		{
			IntPtr onAvatar = ((Il2CppObjectBase)prefab).Pointer;
			GetAllSoundsOfAvatarPrefab(prefab);
			if (_cachePerAvatarByEventEnum.TryGetValue(onAvatar, out Dictionary<AudioEventType, ISet<ReadOnlyAudioEntry>> entriesLookup))
			{
				if (entriesLookup.TryGetValue(singleEventType, out ISet<ReadOnlyAudioEntry> entries))
				{
					foreach (ReadOnlyAudioEntry item in entries)
					{
						yield return item;
					}
				}
				else
				{
					Log.Trace("Missing sound set in enum cache. Skipping.");
				}
			}
			else
			{
				Log.Trace("Missing avatar in enum cache. Skipping.");
			}
		}
	}
	[Flags]
	public enum AudioEventType
	{
		[InspectorName("Declare a custom event name...")]
		Custom = 0,
		[InspectorName("Projectile Damage (hitbullet)")]
		[EventName("hitbullet")]
		HitBullet = 1,
		[InspectorName("Non-Projectile Damage (hitblunt)")]
		[EventName("hitblunt")]
		HitBlunt = 2,
		[InspectorName("Any Damage (hitany)")]
		[EventName("hitany")]
		HitAny = 4,
		[InspectorName("Switching Avatar (spawn)")]
		[EventName("spawn")]
		Spawn = 8
	}
	[AttributeUsage(AttributeTargets.Field)]
	public sealed class EventNameAttribute : Attribute
	{
		public readonly string name;

		public EventNameAttribute(string name)
		{
			this.name = name;
		}
	}
	public static class AudioEventTypeExt
	{
		public static readonly int MAX_FLAG;

		public static readonly ReadOnlyReferenceSpan<AudioEventType> ALL_FLAGS;

		public static readonly ReadOnlyReferenceSpan<string> ALL_FLAGS_EVENT_NAMES;

		private static readonly Dictionary<AudioEventType, string> _nameLookup;

		private static readonly Dictionary<string, AudioEventType> _valueLookup;

		static AudioEventTypeExt()
		{
			Type typeFromHandle = typeof(AudioEventType);
			AudioEventType[] array = new AudioEventType[32];
			string[] array2 = new string[32];
			Log.Trace("Starting up the audio type extension.");
			int num = 0;
			for (int i = 0; i < 32; i++)
			{
				AudioEventType audioEventType = (AudioEventType)(1 << i);
				if (Enum.IsDefined(typeFromHandle, audioEventType))
				{
					num = i;
					array[i] = audioEventType;
					FieldInfo field = typeFromHandle.GetField(Enum.GetName(typeFromHandle, audioEventType));
					EventNameAttribute customAttribute = field.GetCustomAttribute<EventNameAttribute>();
					if (customAttribute != null)
					{
						array2[i] = customAttribute.name;
					}
					else
					{
						array2[i] = string.Empty;
					}
					Log.Trace($"Associated {audioEventType} as {array2[i]}.");
					continue;
				}
				Log.Trace($"Found all of the types ({audioEventType} is not a defined value)");
				break;
			}
			Array.Resize(ref array, num + 1);
			Array.Resize(ref array2, num + 1);
			MAX_FLAG = num;
			ALL_FLAGS = new ReadOnlyReferenceSpan<AudioEventType>(array);
			ALL_FLAGS_EVENT_NAMES = new ReadOnlyReferenceSpan<string>(array2);
			_nameLookup = new Dictionary<AudioEventType, string>();
			_valueLookup = new Dictionary<string, AudioEventType>();
			for (int j = 0; j <= num; j++)
			{
				_nameLookup[ALL_FLAGS[j]] = ALL_FLAGS_EVENT_NAMES[j];
				_valueLookup[ALL_FLAGS_EVENT_NAMES[j]] = ALL_FLAGS[j];
			}
		}

		public static bool TryGetNameFromSingleFlag(AudioEventType flag, out string? result)
		{
			if ((flag & (flag - 1)) != 0)
			{
				throw new ArgumentException($"There is more than one flag set ({flag:G}).");
			}
			if (flag > ALL_FLAGS[ALL_FLAGS.Length - 1])
			{
				result = null;
				return false;
			}
			return _nameLookup.TryGetValue(flag, out result);
		}

		public static bool TryGetFromName(string name, out AudioEventType result)
		{
			return _valueLookup.TryGetValue(name, out result);
		}
	}
	public enum AudioMixerTarget
	{
		[InspectorName("Master")]
		Master,
		[InspectorName("Gunshot")]
		Gunshot,
		[InspectorName("Music")]
		Music,
		[InspectorName("Other SFX")]
		SFX
	}
	public static class AudioMixerTargetExt
	{
		public static AudioMixerGroup GetMixerForTarget(this AudioMixerTarget target)
		{
			return (AudioMixerGroup)(target switch
			{
				AudioMixerTarget.Gunshot => Audio.GunshotMixer, 
				AudioMixerTarget.Music => Audio.MusicMixer, 
				AudioMixerTarget.SFX => Audio.SFXMixer, 
				_ => Audio.MasterMixer, 
			});
		}
	}
	public enum AudioPlayType
	{
		[InspectorName("Declare a custom delegate...")]
		Custom,
		[InspectorName("Choose One Randomly")]
		Random,
		[InspectorName("Play All At Once")]
		AllTogether
	}
	public readonly ref struct AvatarAndPrefabPair
	{
		public readonly Avatar prefab;

		public readonly Avatar clone;

		public AvatarAndPrefabPair(Avatar prefab, Avatar clone)
		{
			if (!prefab.IsPrefabAvatar())
			{
				throw new ArgumentException("The provided prefab was not actually a prefab; it seems to be a runtime instance.", "prefab");
			}
			if (clone.IsPrefabAvatar())
			{
				throw new ArgumentException("The provided clone was actually a prefab; it seems to be a stored crate.", "clone");
			}
			this.prefab = prefab;
			this.clone = clone;
		}

		public AvatarAndPrefabPair(Avatar clone)
		{
			if (clone.IsPrefabAvatar())
			{
				throw new ArgumentException("The provided clone was actually a prefab; it seems to be a stored crate.", "clone");
			}
			Avatar originalPrefab = clone.GetOriginalPrefab();
			if ((Object)(object)originalPrefab == (Object)null)
			{
				throw new NullReferenceException("Failed to resolve the original prefab from the provided clone avatar " + ((Object)clone).name);
			}
			prefab = originalPrefab;
			this.clone = clone;
		}
	}
	[AttributeUsage(AttributeTargets.Field)]
	internal sealed class InspectorNameAttribute : Attribute
	{
		public readonly string name;

		public InspectorNameAttribute(string name)
		{
			this.name = name;
		}
	}
	public sealed class ReadOnlyReferenceSpan<T> : IEnumerable<T>, IEnumerable
	{
		private readonly T[] _array;

		public int Length => _array.Length;

		public T this[int index] => _array[index];

		public ReadOnlyReferenceSpan(T[] array)
		{
			_array = array;
		}

		public int IndexOf(T item)
		{
			return Array.IndexOf(_array, item);
		}

		public IEnumerator<T> GetEnumerator()
		{
			return ((IEnumerable<T>)_array).GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return _array.GetEnumerator();
		}
	}
	public sealed class ReadOnlyAudioEntry
	{
		private readonly Il2CppReferenceArray<AudioClip> _keepAlive;

		private readonly Il2CppReferenceArray<AudioSource>? _sourceKeepAlive;

		public string Name { get; }

		public bool UseCustomPlayType => PlayType == AudioPlayType.Custom;

		public AudioPlayType PlayType { get; }

		public string? CustomPlayType { get; }

		public AudioEventType EventType { get; }

		public string? CustomEventTypes { get; }

		public ReadOnlyHashSet<string> ResolvedCustomEvents { get; }

		public IReadOnlyList<AudioClip> Sounds { get; }

		public Vector2 PitchRange { get; }

		public float Volume { get; }

		public AudioMixerTarget Mixer { get; } = AudioMixerTarget.SFX;


		public SoundFlags SoundFlags { get; } = SoundFlags.FollowEmitter | SoundFlags.RealtimePitchShift;


		public AudioSource? OverrideTemplateAudioSource { get; }

		internal ReadOnlyAudioEntry(AudioEntry real)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			Name = real.Name;
			PlayType = real.PlayType;
			CustomPlayType = real.CustomPlayType;
			CustomEventTypes = real.CustomEventTypes;
			Sounds = new ReadOnlyCollection<AudioClip>(new List<AudioClip>(real.Sounds));
			PitchRange = real.PitchRange;
			Volume = real.Volume;
			OverrideTemplateAudioSource = (Object.op_Implicit((Object)(object)OverrideTemplateAudioSource) ? Object.Instantiate<AudioSource>(OverrideTemplateAudioSource) : null);
			Mixer = real.Mixer;
			SoundFlags soundFlags = real.SoundFlags;
			if (soundFlags.HasFlag(SoundFlags.RealtimePitchShift))
			{
				soundFlags |= SoundFlags.PitchShift;
			}
			SoundFlags = soundFlags;
			SoundBlockNameSanitizer.CreateStringAndEnumMix(CustomEventTypes ?? string.Empty, out string[] customs, out AudioEventType enums);
			EventType = enums | real.EventType;
			ResolvedCustomEvents = new ReadOnlyHashSet<string>(customs);
			_keepAlive = new Il2CppReferenceArray<AudioClip>(Sounds.ToArray());
			if ((Object)(object)OverrideTemplateAudioSource != (Object)null)
			{
				_sourceKeepAlive = new Il2CppReferenceArray<AudioSource>((AudioSource[])(object)new AudioSource[1] { OverrideTemplateAudioSource });
			}
		}
	}
	[Serializable]
	public sealed class SerializableAudioArray
	{
		public List<AudioClip> clips;

		public List<AudioClip> Clips
		{
			[MemberNotNull("clips")]
			get
			{
				return clips ?? (clips = new List<AudioClip>());
			}
			[MemberNotNull("clips")]
			set
			{
				clips = value ?? new List<AudioClip>();
			}
		}

		public AudioClip this[int index]
		{
			get
			{
				return Clips[index];
			}
			set
			{
				Clips[index] = value;
			}
		}

		internal static void CallToStaticallyInitialize()
		{
		}

		public SerializableAudioArray()
		{
			clips = new List<AudioClip>();
		}
	}
	[Serializable]
	public sealed class SerializableAudioArray2D
	{
		public SerializableAudioArray[] children;

		public SerializableAudioArray[] Children
		{
			[MemberNotNull("children")]
			get
			{
				return children ?? (children = Array.Empty<SerializableAudioArray>());
			}
			[MemberNotNull("children")]
			set
			{
				children = value ?? Array.Empty<SerializableAudioArray>();
			}
		}

		public SerializableAudioArray this[int index]
		{
			get
			{
				return Children[index];
			}
			set
			{
				Children[index] = value;
			}
		}

		internal static void CallToStaticallyInitialize()
		{
		}

		public SerializableAudioArray2D()
		{
			children = Array.Empty<SerializableAudioArray>();
		}
	}
	[Flags]
	public enum SoundFlags
	{
		None = 0,
		FollowEmitter = 1,
		PitchShift = 2,
		RealtimePitchShift = 4
	}
}
namespace AvatarStatExtender.BuiltInEvents
{
	internal static class SoundBroadcastMarshaller
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static DamageReceptionDelegate <0>__OnDamageTaken;

			public static Action<Avatar> <1>__AfterSwitchingAvatar;
		}

		internal static void Initialize()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			Log.Info("Initializing the sound broadcast marshaller.");
			object obj = <>O.<0>__OnDamageTaken;
			if (obj == null)
			{
				DamageReceptionDelegate val = OnDamageTaken;
				<>O.<0>__OnDamageTaken = val;
				obj = (object)val;
			}
			DamageReceptionHelper.OnDamageTaken += (DamageReceptionDelegate)obj;
			Hooking.OnSwitchAvatarPostfix += AfterSwitchingAvatar;
		}

		private static void OnDamageTaken(Player_Health health, ref bool attackInfoAndPartAvailable, in ImmutableAttackInfo originalAttack, ref AttackInfo attack, in BodyPart originalPart, ref BodyPart part, EventPhase phase)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)phase != 1)
			{
				return;
			}
			Log.Trace("Damage event phase, after.");
			if (!(((AttackInfo)(ref attack)).Damage > 0f))
			{
				return;
			}
			Avatar avatar = health.GetAvatar();
			if ((Object)(object)avatar == (Object)null)
			{
				Log.Error("Player damage was reported however there was no known victim (the health object does not belong to an avatar?) Name: " + ((Object)health).name);
				return;
			}
			if (((Enum)((AttackInfo)(ref attack)).DamageType).HasFlag((Enum)(object)(AttackType)1))
			{
				Log.Trace("Broadcasting hit bullet impact sound to " + ((Object)avatar).name + ".");
				SoundAPI.BroadcastBuiltInSoundEvent(AudioEventType.HitBullet, avatar);
			}
			else
			{
				Log.Trace("Broadcasting hit non-bullet impact sound to " + ((Object)avatar).name + ".");
				SoundAPI.BroadcastBuiltInSoundEvent(AudioEventType.HitBlunt, avatar);
			}
			Log.Trace("Broadcasting general hit sound to " + ((Object)avatar).name + ".");
			SoundAPI.BroadcastBuiltInSoundEvent(AudioEventType.HitAny, avatar);
		}

		private static void AfterSwitchingAvatar(Avatar avatar)
		{
			if (!((Object)(object)avatar == (Object)null) && !((Object)(object)avatar.GetRigManager() == (Object)null) && !avatar.IsPrefabAvatar())
			{
				Log.Info("Broadcasting spawn sound to " + ((Object)avatar).name + ".");
				SoundAPI.BroadcastBuiltInSoundEvent(AudioEventType.Spawn, avatar);
			}
		}
	}
}
namespace AvatarStatExtender.API
{
	public static class SoundAPI
	{
		public delegate PlayableSoundData[] AudioSelectionDelegate(Avatar avatar, string playTypeName, AudioEventType vanillaEvent, string? customEvent, ReadOnlyAudioEntry triggeredGroup);

		public static readonly AudioSelectionDelegate PLAYTYPE_DEFAULT_RANDOM = (Avatar _, string _, AudioEventType _, string? _, ReadOnlyAudioEntry group) => new PlayableSoundData[1]
		{
			new PlayableSoundData(group, Random.RandomRangeInt(0, group.Sounds.Count - 1), group.SoundFlags, group.Mixer.GetMixerForTarget())
		};

		public static readonly AudioSelectionDelegate PLAYTYPE_DEFAULT_ALL = delegate(Avatar _, string _, AudioEventType _, string? _, ReadOnlyAudioEntry group)
		{
			ReadOnlyAudioEntry group2 = group;
			return group2.Sounds.Select((AudioClip sound) => new PlayableSoundData(sound, group2.Volume, group2.PitchRange, group2.SoundFlags, group2.Mixer.GetMixerForTarget())).ToArray();
		};

		private static readonly Dictionary<string, AudioSelectionDelegate> _delegates = new Dictionary<string, AudioSelectionDelegate>();

		public static IList<GameObject> BroadcastSoundEvent(string name, params Avatar[] toAvatars)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				throw new ArgumentNullException("name");
			}
			if (!SoundBlockNameSanitizer.IsSane(name))
			{
				throw new ArgumentOutOfRangeException("name", "Only one name is allowed, not a list. Names must be all lowercase, and contain only alphanumeric characters, periods, dashes, or underscores. Names may also have a single colon (:) splitting the name, for namespace:sound.");
			}
			string text = name;
			if (AudioEventTypeExt.TryGetFromName(name, out var result))
			{
				text = null;
			}
			List<GameObject> list = new List<GameObject>();
			object obj;
			if (toAvatars == null || toAvatars.Length == 0 || !toAvatars.Any((Avatar avy) => (Object)(object)avy != (Object)null))
			{
				obj = PlayerObjectExtensions.GetAllActiveAvatars();
			}
			else
			{
				obj = toAvatars;
			}
			IEnumerable<Avatar> enumerable = (IEnumerable<Avatar>)obj;
			foreach (Avatar item in enumerable)
			{
				if (!((Object)(object)item == (Object)null))
				{
					AvatarAndPrefabPair avatarAndPrefabPair = new AvatarAndPrefabPair(item);
					IEnumerable<ReadOnlyAudioEntry> enumerable2;
					if (text != null)
					{
						enumerable2 = AudioCache.GetMatchingSoundsFromAvatarSingle(avatarAndPrefabPair.prefab, text);
					}
					else
					{
						IEnumerable<ReadOnlyAudioEntry> enumerable3 = Array.Empty<ReadOnlyAudioEntry>();
						enumerable2 = enumerable3;
					}
					IEnumerable<ReadOnlyAudioEntry> entries = enumerable2;
					IEnumerable<GameObject> collection = BroadcastEntriesOf(avatarAndPrefabPair.prefab, avatarAndPrefabPair.clone, entries, result, text);
					list.AddRange(collection);
				}
			}
			return list;
		}

		internal static IList<GameObject> BroadcastBuiltInSoundEvent(AudioEventType builtInEvents, params Avatar[] toAvatars)
		{
			if (builtInEvents != 0)
			{
				if ((builtInEvents & (builtInEvents - 1)) != 0)
				{
					throw new ArgumentOutOfRangeException("builtInEvents", "Only one flag can be set at a time.");
				}
				List<GameObject> list = new List<GameObject>();
				object obj;
				if (toAvatars == null || toAvatars.Length == 0 || !toAvatars.Any((Avatar avy) => (Object)(object)avy != (Object)null))
				{
					obj = PlayerObjectExtensions.GetAllActiveAvatars();
				}
				else
				{
					obj = toAvatars;
				}
				IEnumerable<Avatar> enumerable = (IEnumerable<Avatar>)obj;
				foreach (Avatar item in enumerable)
				{
					if (!((Object)(object)item == (Object)null))
					{
						AvatarAndPrefabPair avatarAndPrefabPair = new AvatarAndPrefabPair(item);
						IEnumerable<ReadOnlyAudioEntry> matchingSoundsFromAvatarSingle = AudioCache.GetMatchingSoundsFromAvatarSingle(avatarAndPrefabPair.prefab, builtInEvents);
						IEnumerable<GameObject> collection = BroadcastEntriesOf(avatarAndPrefabPair.prefab, avatarAndPrefabPair.clone, matchingSoundsFromAvatarSingle, builtInEvents, null);
						list.AddRange(collection);
					}
				}
				return list;
			}
			return (IList<GameObject>)ListTools.EmptyReadOnly<GameObject>();
		}

		private static IEnumerable<GameObject> BroadcastEntriesOf(Avatar prefab, Avatar clone, IEnumerable<ReadOnlyAudioEntry> entries, AudioEventType vanillaSource, string? customSource)
		{
			Log.Trace($"Broadcasting sounds to {((Object)prefab).name} ({vanillaSource}, {customSource})");
			foreach (ReadOnlyAudioEntry entry in entries)
			{
				PlayableSoundData[] sounds = Array.Empty<PlayableSoundData>();
				if (entry.UseCustomPlayType)
				{
					string customPlayType = entry.CustomPlayType;
					if (!string.IsNullOrWhiteSpace(customPlayType))
					{
						if (_delegates.TryGetValue(customPlayType, out AudioSelectionDelegate selector))
						{
							try
							{
								sounds = selector(clone, customPlayType, vanillaSource, customSource, entry);
								Log.Trace($"Custom selector picked {sounds.Length} sound(s).");
							}
							catch (Exception ex)
							{
								Exception err = ex;
								Log.Error("A custom sound selector for sound group " + entry.Name + " (of " + ((Object)prefab).name + ") raised an exception while picking audio.");
								Log.Error(err);
							}
						}
						else
						{
							Log.Warn("Sound group " + entry.Name + " (of " + ((Object)prefab).name + ") wanted to play a sound with a custom selector, but no such selector '" + entry.CustomPlayType + "' exists. This sound will be skipped.");
						}
						selector = null;
					}
					else
					{
						Log.Warn("Sound group " + entry.Name + " (of " + ((Object)prefab).name + ") wanted to play a sound with a custom selector, but its selector string was null or whitespace.");
					}
				}
				else if (entry.PlayType == AudioPlayType.Random)
				{
					Log.Trace("Choosing one random sound.");
					sounds = PLAYTYPE_DEFAULT_RANDOM(clone, "Internal Random Selector", vanillaSource, customSource, entry);
				}
				else if (entry.PlayType == AudioPlayType.AllTogether)
				{
					Log.Trace("Choosing all sounds.");
					sounds = PLAYTYPE_DEFAULT_ALL(clone, "Internal All Selector", vanillaSource, customSource, entry);
				}
				else
				{
					Log.Warn($"Sound group {entry.Name} (of {((Object)prefab).name}) wanted to play a sound with a built-in selector, but the index of the selector ({entry.PlayType:X8}) was undefined. This sound will be skipped.");
				}
				RigManager mgr = clone.GetRigManager();
				if ((Object)(object)mgr == (Object)null)
				{
					Log.Error($"Avatar {clone} has no rig manager? Failed to play sound.");
					continue;
				}
				RealtimeSkeletonRig realHepta = mgr.realHeptaRig;
				if ((Object)(object)realHepta == (Object)null)
				{
					Log.Error($"Avatar {clone} has no real hepta rig? Failed to play sound.");
					continue;
				}
				Transform chest = ((Rig)realHepta).m_chest;
				if ((Object)(object)chest == (Object)null)
				{
					Log.Error($"Avatar {clone} has no chest set in its real hepta rig? Failed to play sound.");
					continue;
				}
				Log.Trace($"Playing {sounds.Length} sound(s).");
				for (int i = 0; i < sounds.Length; i++)
				{
					PlayableSoundData sound = sounds[i];
					if ((Object)(object)sound.sound == (Object)null)
					{
						Log.Error("A playable sound clip's sound was missing for entry " + entry.Name + " (on avatar " + ((Object)prefab).name + "); was it returned as null? Was it garbage collected on the il2cpp side?");
					}
					else
					{
						ref AudioMixerGroup mixer = ref sound.mixer;
						if (mixer == null)
						{
							mixer = entry.Mixer.GetMixerForTarget();
						}
						yield return SoundPlayerSystem.PlaySound(chest, sound, entry.OverrideTemplateAudioSource);
					}
				}
			}
		}

		public static void RegisterSoundPlayTypeSelectionHandler(string playType, AudioSelectionDelegate

Mods/XansTools.dll

Decompiled 9 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using SLZ.AI;
using SLZ.Combat;
using SLZ.Marrow.Data;
using UnhollowerBaseLib;
using UnityEngine;
using XansTools;
using XansTools.Data;
using XansTools.Patching;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("DamageReactivity")]
[assembly: ComVisible(false)]
[assembly: Guid("a55e452e-2b5a-4b67-bfbc-8d84d3c461e2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: MelonInfo(typeof(XTCore), "Xan's Tools", "1.0.0", "Xan", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonPriority(1)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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;
		}
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[AttributeUsage(AttributeTargets.All)]
	public sealed class IsUnmanagedAttribute : Attribute
	{
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
	public sealed class AllowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	public sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	public sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
}
namespace XansTools
{
	public static class Log
	{
		private static Instance _log;

		internal static void Initialize(Instance log)
		{
			_log = log;
		}

		public static void Info(object msg)
		{
			_log.Msg(msg);
		}

		public static void Info(string msg)
		{
			_log.Msg(msg);
		}

		public static void Warn(object msg)
		{
			_log.Warning(msg);
		}

		public static void Warn(string msg)
		{
			_log.Warning(msg);
		}

		public static void Error(object msg)
		{
			_log.Error(msg);
		}

		public static void Error(string msg)
		{
			_log.Error(msg);
		}

		public static void Debug(object msg)
		{
			_log.Msg(ConsoleColor.Gray, msg);
		}

		public static void Debug(string msg)
		{
			_log.Msg(ConsoleColor.Gray, msg);
		}

		public static void Trace(object msg)
		{
			if (Prefs.TraceLogging)
			{
				_log.Msg(ConsoleColor.DarkGray, msg);
			}
		}

		public static void Trace(string msg)
		{
			if (Prefs.TraceLogging)
			{
				_log.Msg(ConsoleColor.DarkGray, msg);
			}
		}
	}
	public static class Prefs
	{
		private static MelonPreferences_Entry<bool> _traceLogging;

		public static bool TraceLogging => _traceLogging.Value;

		internal static void Initialize()
		{
			MelonPreferences_Category val = MelonPreferences.CreateCategory("xanstools_main");
			val.DisplayName = "Main Settings";
			_traceLogging = val.CreateEntry<bool>("traceLogging", true, "Trace Logging", "Trace Logging causes extremely (like, comically) specific things to be written into the console." + Environment.NewLine + "This tends to flood the console with information that is useless normally, but it is very useful for debugging.", false, false, (ValueValidator)null, (string)null);
		}
	}
	public class XTCore : MelonMod
	{
		public override void OnInitializeMelon()
		{
			((MelonBase)this).OnInitializeMelon();
			Prefs.Initialize();
			Log.Initialize(((MelonBase)this).LoggerInstance);
			DamageReactionFacilitator.Patch();
		}
	}
}
namespace XansTools.Patching
{
	internal static class DamageReactionFacilitator
	{
		public delegate void PlayerDamageTakenDelegate(Player_Health @this, in ImmutableAttackInfo originalAttack, ref AttackInfo attack, in BodyPart originalPart, ref BodyPart part, EventPhase phase);

		public delegate void PlayerTAKEDAMAGEDelegate(Player_Health @this, in float originalAmount, ref float amount, EventPhase phase);

		private delegate void CommonDamageTakenDelegate(IntPtr @this, IntPtr attack, BodyPart part, IntPtr method);

		private delegate void CommonTAKEDAMAGEDelegate(IntPtr @this, float damage, IntPtr method);

		private const string METHOD_PTR_FLD_NAME_PLAYER = "NativeMethodInfoPtr_OnReceivedDamage_Public_Virtual_Void_Attack_BodyPart_0";

		private const string METHOD_PTR_FLD_NAME_ENEMY = "NativeMethodInfoPtr_OnReceivedDamage_Public_Void_Attack_BodyPart_0";

		private const string METHOD_PTR_FLD_NAME_PLAYER_TAKEDAMAGE = "NativeMethodInfoPtr_TAKEDAMAGE_Public_Virtual_Void_Single_0";

		private static CommonDamageTakenDelegate? _originalPlayerDamageTaken;

		private static CommonTAKEDAMAGEDelegate? _originalPlayerTAKEDAMAGE;

		public static event PlayerDamageTakenDelegate? OnPlayerDamageTaken;

		public static event PlayerTAKEDAMAGEDelegate? OnPlayerTAKEDAMAGECalled;

		internal static void Patch()
		{
			Log.Info("Damage Reaction Facilitator is performing patches.");
			CommonDamageTakenDelegate detour = OnPlayerDamageReceived;
			CommonTAKEDAMAGEDelegate detour2 = PlayerTAKEDAMAGECalled;
			_originalPlayerDamageTaken = Utils.NativeHookAttachFrom<Player_Health, CommonDamageTakenDelegate>("NativeMethodInfoPtr_OnReceivedDamage_Public_Virtual_Void_Attack_BodyPart_0", detour);
			_originalPlayerTAKEDAMAGE = Utils.NativeHookAttachFrom<Player_Health, CommonTAKEDAMAGEDelegate>("NativeMethodInfoPtr_TAKEDAMAGE_Public_Virtual_Void_Single_0", detour2);
		}

		private static void PlayerTAKEDAMAGECalled(IntPtr @this, float damage, IntPtr method)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			Log.Trace("Executing TAKEDAMAGE phase: Before...");
			Thread.BeginCriticalRegion();
			Player_Health this2 = new Player_Health(@this);
			float originalAmount = damage;
			try
			{
				DamageReactionFacilitator.OnPlayerTAKEDAMAGECalled?.Invoke(this2, in originalAmount, ref damage, EventPhase.Before);
			}
			catch (Exception msg)
			{
				Log.Error("Failed to execute OnPlayerTAKEDAMAGECalled phase: Before!");
				Log.Error(msg);
			}
			Log.Trace("Invoking original TAKEDAMAGE...");
			_originalPlayerTAKEDAMAGE(@this, damage, method);
			Log.Trace("Executing TAKEDAMAGE phase: After...");
			try
			{
				DamageReactionFacilitator.OnPlayerTAKEDAMAGECalled?.Invoke(this2, in originalAmount, ref damage, EventPhase.After);
			}
			catch (Exception msg2)
			{
				Log.Error("Failed to execute OnPlayerTAKEDAMAGECalled phase: After!");
				Log.Error(msg2);
			}
			Thread.EndCriticalRegion();
		}

		private unsafe static void OnPlayerDamageReceived(IntPtr @this, IntPtr attack, BodyPart part, IntPtr method)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0028: 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)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			Thread.BeginCriticalRegion();
			Player_Health this2 = new Player_Health(@this);
			AttackInfo* ptr = (AttackInfo*)(void*)attack;
			AttackInfo attack2 = *ptr;
			AttackInfo attackInfo = attack2;
			ImmutableAttackInfo originalAttack = System.Runtime.CompilerServices.Unsafe.Read<ImmutableAttackInfo>(&attackInfo);
			BodyPart originalPart = part;
			Log.Trace("Executing player damage phase: Before...");
			try
			{
				DamageReactionFacilitator.OnPlayerDamageTaken?.Invoke(this2, in originalAttack, ref attack2, in originalPart, ref part, EventPhase.Before);
			}
			catch (Exception msg)
			{
				Log.Error("Failed to execute OnPlayerDamageTaken phase: Before!");
				Log.Error(msg);
			}
			System.Runtime.CompilerServices.Unsafe.Write(ptr, attack2);
			Log.Trace("Executing original player damage method...");
			_originalPlayerDamageTaken(@this, (IntPtr)ptr, part, method);
			attack2 = *ptr;
			Log.Trace("Executing player damage phase: After...");
			try
			{
				DamageReactionFacilitator.OnPlayerDamageTaken?.Invoke(this2, in originalAttack, ref attack2, in originalPart, ref part, EventPhase.After);
			}
			catch (Exception msg2)
			{
				Log.Error("Failed to execute OnPlayerDamageTaken phase: After!");
				Log.Error(msg2);
			}
			Thread.EndCriticalRegion();
		}
	}
}
namespace XansTools.Data
{
	public struct AttackInfo
	{
		private float _damage;

		private Vector3 _normal;

		private Vector3 _origin;

		private Vector3 _direction;

		private byte _backFacing;

		private int _orderInPool;

		private IntPtr _collider;

		private AttackType _attackType;

		private IntPtr _proxy;

		public float Damage
		{
			get
			{
				return _damage;
			}
			set
			{
				_damage = value;
			}
		}

		public Vector3 Normal
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _normal;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				_normal = value;
			}
		}

		public Vector3 Direction
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _direction;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				_direction = value;
			}
		}

		public Vector3 Origin
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _origin;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				_origin = value;
			}
		}

		public bool IsBackFacing
		{
			get
			{
				return _backFacing == 1;
			}
			set
			{
				_backFacing = (byte)(value ? 1u : 0u);
			}
		}

		public int OrderInAttackPool
		{
			get
			{
				return _orderInPool;
			}
			set
			{
				_orderInPool = value;
			}
		}

		public Collider Collider
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Expected O, but got Unknown
				return new Collider(_collider);
			}
			set
			{
				_collider = ((Il2CppObjectBase)value).Pointer;
			}
		}

		public AttackType DamageType
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _attackType;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				_attackType = value;
			}
		}

		public TriggerRefProxy Proxy
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Expected O, but got Unknown
				return new TriggerRefProxy(_proxy);
			}
			set
			{
				_proxy = ((Il2CppObjectBase)value).Pointer;
			}
		}

		public unsafe static AttackInfo Fix(Attack attack)
		{
			AttackInfo* ptr = (AttackInfo*)(void*)((Il2CppObjectBase)attack).Pointer;
			return *ptr;
		}

		public unsafe static AttackInfo From(IntPtr attack)
		{
			AttackInfo* ptr = (AttackInfo*)(void*)attack;
			return *ptr;
		}
	}
	public readonly struct ImmutableAttackInfo
	{
		private readonly float _damage;

		private readonly Vector3 _normal;

		private readonly Vector3 _origin;

		private readonly Vector3 _direction;

		private readonly byte _backFacing;

		private readonly int _orderInPool;

		private readonly IntPtr _collider;

		private readonly AttackType _attackType;

		private readonly IntPtr _proxy;

		public float Damage => _damage;

		public Vector3 Normal => _normal;

		public Vector3 Direction => _direction;

		public Vector3 Origin => _origin;

		public bool IsBackFacing => _backFacing == 1;

		public int OrderInAttackPool => _orderInPool;

		public Collider Collider => new Collider(_collider);

		public AttackType DamageType => _attackType;

		public TriggerRefProxy Proxy => new TriggerRefProxy(_proxy);
	}
	public enum EventPhase
	{
		Before,
		After
	}
	public static class MethodOfProvider
	{
		private static readonly ConditionalWeakTable<MethodInfo, MethodBase> _methods = new ConditionalWeakTable<MethodInfo, MethodBase>();

		private static readonly Type[] _getMethodFromHandleParams = new Type[1] { typeof(RuntimeMethodHandle) };

		private static MethodInfo? _getMethodFromHandle = null;

		public static MethodBase methodof<T>(T del) where T : Delegate
		{
			if ((Delegate?)del == (Delegate?)null)
			{
				throw new ArgumentNullException("del");
			}
			MethodInfo methodInfo = del.GetMethodInfo();
			if ((object)methodInfo == null)
			{
				throw new ArgumentException("The provided delegate's method was null!");
			}
			if (_methods.TryGetValue(methodInfo, out MethodBase value))
			{
				return value;
			}
			DynamicMethod dynamicMethod = new DynamicMethod($"<{methodInfo}>methodof", typeof(MethodBase), Array.Empty<Type>());
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if ((object)_getMethodFromHandle == null)
			{
				_getMethodFromHandle = typeof(MethodBase).GetMethod("GetMethodFromHandle", BindingFlags.Static | BindingFlags.Public, null, _getMethodFromHandleParams, null);
			}
			iLGenerator.Emit(OpCodes.Ldtoken, methodInfo);
			iLGenerator.Emit(OpCodes.Call, _getMethodFromHandle);
			iLGenerator.Emit(OpCodes.Ret);
			Func<MethodBase> func = (Func<MethodBase>)dynamicMethod.CreateDelegate(typeof(Func<MethodBase>));
			MethodBase methodBase = func();
			_methods.Add(methodInfo, methodBase);
			return methodBase;
		}
	}
	[Obsolete("This is not yet ready and may not actually be used.")]
	public sealed class BlamedEvent<TArgs, TReturn>
	{
		internal delegate void UpdateArgsPackageDelegate(in TReturn retIn, ref TArgs argsPackage);

		public class Accessor
		{
			internal sealed class ModOwnedSubscriber : IEquatable<ModOwnedSubscriber>
			{
				public Accessor Owner { get; }

				public MelonMod Mod { get; }

				public Func<TArgs, EventPhase, TReturn> Callback { get; }

				public ModOwnedSubscriber(Accessor owner, MelonMod mod, Func<TArgs, EventPhase, TReturn> callback, bool unsubscribeAutomaticallyIfMelonUnloaded = true)
				{
					Owner = owner;
					Mod = mod;
					Callback = callback;
					if (unsubscribeAutomaticallyIfMelonUnloaded)
					{
						SetupAutoUnsubscribe();
					}
				}

				internal void SetupAutoUnsubscribe()
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Expected O, but got Unknown
					((MelonEventBase<LemonAction>)(object)((MelonBase)Mod).OnUnregister).Subscribe((LemonAction)delegate
					{
						Owner.UnsubscribeAll(this);
					}, 0, true);
				}

				public override bool Equals(object obj)
				{
					if (obj is Accessor obj2)
					{
						return Equals(obj2);
					}
					return false;
				}

				public override int GetHashCode()
				{
					return (int)((long)((object)Mod).GetHashCode() * (long)Callback.GetHashCode());
				}

				public bool Equals(ModOwnedSubscriber? other)
				{
					if ((object)other == null)
					{
						return false;
					}
					return Owner == other.Owner && Mod == other.Mod;
				}

				public static bool operator ==(ModOwnedSubscriber? left, ModOwnedSubscriber? right)
				{
					return left?.Equals(right) ?? false;
				}

				public static bool operator !=(ModOwnedSubscriber? left, ModOwnedSubscriber? right)
				{
					return !(left == right);
				}
			}

			private readonly Dictionary<Func<TArgs, EventPhase, TReturn>, (ModOwnedSubscriber?, ModOwnedSubscriber?)> _subscribersByDelegate = new Dictionary<Func<TArgs, EventPhase, TReturn>, (ModOwnedSubscriber, ModOwnedSubscriber)>();

			public BlamedEvent<TArgs, TReturn> Owner { get; }

			public MelonMod Mod { get; }

			internal Accessor(BlamedEvent<TArgs, TReturn> owner, MelonMod mod)
			{
				Owner = owner;
				Mod = mod;
			}

			internal IEnumerable<ModOwnedSubscriber> GetSubscribers(EventPhase phase)
			{
				foreach (var subscriber in _subscribersByDelegate.Values)
				{
					ModOwnedSubscriber target = null;
					switch (phase)
					{
					case EventPhase.Before:
						(target, _) = subscriber;
						break;
					case EventPhase.After:
						target = subscriber.Item2;
						break;
					}
					if (target != null)
					{
						yield return target;
					}
				}
			}

			public void Subscribe(Func<TArgs, EventPhase, TReturn> @delegate, EventPhase phase, bool unsubscribeAutomaticallyIfMelonUnloaded = true)
			{
				if (@delegate == null)
				{
					throw new ArgumentNullException("delegate");
				}
				if (phase != 0 && phase != EventPhase.After)
				{
					throw new ArgumentOutOfRangeException("phase", "Invalid event phase.");
				}
				if (_subscribersByDelegate.TryGetValue(@delegate, out (ModOwnedSubscriber, ModOwnedSubscriber) value))
				{
					bool flag = false;
					switch (phase)
					{
					case EventPhase.Before:
						flag = value.Item1 != null;
						break;
					case EventPhase.After:
						flag = value.Item2 != null;
						break;
					}
					if (flag)
					{
						throw new InvalidOperationException($"Mod [{((MelonBase)Mod).ID}] tried to subscribe to event {Owner.Name} with the same delegate more than once for the same phase ({phase}). You can only subscribe any given method once for a phase.");
					}
				}
				ModOwnedSubscriber modOwnedSubscriber = new ModOwnedSubscriber(this, Mod, @delegate, unsubscribeAutomaticallyIfMelonUnloaded);
				value = default((ModOwnedSubscriber, ModOwnedSubscriber));
				if (phase == EventPhase.Before)
				{
					value.Item1 = modOwnedSubscriber;
				}
				else
				{
					value.Item2 = modOwnedSubscriber;
				}
				_subscribersByDelegate[@delegate] = value;
			}

			public void Unsubscribe(Func<TArgs, EventPhase, TReturn> @delegate, EventPhase phase)
			{
				Unsubscribe(@delegate, phase, softFail: false);
			}

			private void Unsubscribe(Func<TArgs, EventPhase, TReturn> @delegate, EventPhase phase, bool softFail)
			{
				if (@delegate == null)
				{
					throw new ArgumentNullException("delegate");
				}
				if (phase != 0 && phase != EventPhase.After)
				{
					throw new ArgumentOutOfRangeException("phase", "Invalid event phase.");
				}
				if (_subscribersByDelegate.TryGetValue(@delegate, out (ModOwnedSubscriber, ModOwnedSubscriber) value))
				{
					if (phase == EventPhase.Before)
					{
						if (value.Item1 != null)
						{
							value.Item1 = null;
						}
						_subscribersByDelegate[@delegate] = value;
					}
					else
					{
						if (value.Item2 != null)
						{
							value.Item2 = null;
						}
						_subscribersByDelegate[@delegate] = value;
					}
				}
				else if (!softFail)
				{
					throw new InvalidOperationException("Mod [" + ((MelonBase)Mod).ID + "] tried to unsubscribe from event " + Owner.Name + " but the provided delegate (Method: " + (@delegate.Method?.Name ?? "<no method>") + ") was not a subscriber.");
				}
			}

			private void UnsubscribeAll(ModOwnedSubscriber subscriber)
			{
				Unsubscribe(subscriber.Callback, EventPhase.Before, softFail: true);
				Unsubscribe(subscriber.Callback, EventPhase.After, softFail: true);
			}
		}

		private readonly Dictionary<MelonMod, Accessor> _accessorCache = new Dictionary<MelonMod, Accessor>();

		public string Name { get; }

		internal UpdateArgsPackageDelegate? UpdateArgsWithReturnValue { get; set; }

		internal BlamedEvent(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				throw new ArgumentException("The name of an event must be a non-null name with at least one or more non-whitespace character(s).");
			}
			Name = name;
		}

		internal void InvokeAll(ref TArgs argsPackage, in EventPhase phase, ref TReturn currentReturnValue)
		{
			foreach (Accessor value in _accessorCache.Values)
			{
				foreach (Accessor.ModOwnedSubscriber subscriber in value.GetSubscribers(phase))
				{
					try
					{
						currentReturnValue = subscriber.Callback(argsPackage, phase);
						UpdateArgsWithReturnValue?.Invoke(in currentReturnValue, ref argsPackage);
					}
					catch (Exception msg)
					{
						try
						{
							((MelonBase)subscriber.Mod).LoggerInstance.Error("This error message has been sent by XansTools so that the Lum log analyzer bot can detect this error as part of this mod. The real error is right below.");
						}
						catch
						{
						}
						Log.Error($"Mod [{((MelonBase)value.Mod).ID}]'s event callback [{subscriber.Callback} ({subscriber.Callback.Method?.Name})] has raised an exception while {Name} was firing {phase} the original method. Exception follows:");
						Log.Error(msg);
					}
				}
			}
		}

		public Accessor GetSubscriptionService(MelonMod yourMod)
		{
			if (yourMod == null)
			{
				throw new ArgumentNullException("yourMod", "You must provide an instance of your mod for error debugging purposes.");
			}
			if (!_accessorCache.TryGetValue(yourMod, out Accessor value))
			{
				return new Accessor(this, yourMod);
			}
			return value;
		}
	}
	public static class Utils
	{
		[Obsolete("Not yet available.")]
		public static string TryGuessMethodNameOf<TDelegate>(TDelegate del) where TDelegate : Delegate
		{
			throw new NotImplementedException("This method is not yet available.");
		}

		public unsafe static TDelegate NativeHookAttachFrom<TMethodOwner, TDelegate>(string ptrFieldName, TDelegate detour) where TDelegate : Delegate
		{
			if ((Delegate?)detour == (Delegate?)null)
			{
				throw new ArgumentNullException("detour");
			}
			if (detour.Method == null)
			{
				throw new InvalidOperationException("Parameter 'detour' does not have a Method?");
			}
			ParameterInfo[] parameters = detour.Method.GetParameters();
			if (parameters.Any((ParameterInfo param) => !param.ParameterType.IsValueType))
			{
				throw new InvalidOperationException("For patch methods, all parameters should be value types. To receive an object type, instead receive IntPtr and then create a pointer to that object.");
			}
			IntPtr ptr = *(IntPtr*)(void*)(IntPtr)typeof(TMethodOwner).GetField(ptrFieldName, BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
			IntPtr functionPointer = detour.Method.MethodHandle.GetFunctionPointer();
			MelonUtils.NativeHookAttach((IntPtr)(&ptr), functionPointer);
			return Marshal.GetDelegateForFunctionPointer<TDelegate>(ptr);
		}
	}
}
namespace XansTools.AvatarInteroperability
{
	public static class DamageReceptionHelper
	{
		public delegate void DamageReceptionDelegate(Player_Health health, ref bool attackInfoAndPartAvailable, in ImmutableAttackInfo originalAttack, ref AttackInfo attack, in BodyPart originalPart, ref BodyPart part, EventPhase phase);

		private static bool _isConnectedToEvents = false;

		private static readonly Stack<Player_Health> _isAboutToExecuteTAKEDAMAGEFromRecv = new Stack<Player_Health>();

		private static readonly HashSet<DamageReceptionDelegate> _delegates = new HashSet<DamageReceptionDelegate>();

		public static event DamageReceptionDelegate OnDamageTaken
		{
			add
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				if (!_delegates.Add(value))
				{
					throw new InvalidOperationException($"Delegate {value} is already subscribed; cannot subscribe it.");
				}
				if (!_isConnectedToEvents)
				{
					_isConnectedToEvents = true;
					DamageReactionFacilitator.OnPlayerDamageTaken += OnContextualDamageTaken;
					DamageReactionFacilitator.OnPlayerTAKEDAMAGECalled += OnAmbiguousDamageTaken;
				}
			}
			remove
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				if (!_delegates.Remove(value))
				{
					throw new InvalidOperationException($"Delegate {value} was not subscribed; cannot unsubscribe it.");
				}
				if (_isConnectedToEvents && _delegates.Count == 0)
				{
					_isConnectedToEvents = false;
					DamageReactionFacilitator.OnPlayerDamageTaken -= OnContextualDamageTaken;
					DamageReactionFacilitator.OnPlayerTAKEDAMAGECalled -= OnAmbiguousDamageTaken;
				}
			}
		}

		private static void ExecuteAllDelegates(Player_Health health, bool attackInfoAndPartAvailable, in ImmutableAttackInfo originalAttack, ref AttackInfo attack, in BodyPart originalPart, ref BodyPart part, EventPhase phase)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected I4, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			foreach (DamageReceptionDelegate @delegate in _delegates)
			{
				AttackInfo attackInfo = attack;
				BodyPart val = part;
				try
				{
					@delegate(health, ref attackInfoAndPartAvailable, in originalAttack, ref attack, in originalPart, ref part, phase);
				}
				catch (Exception msg)
				{
					part = (BodyPart)(int)val;
					attack = attackInfo;
					MelonAssembly melonAssemblyOfMember = MelonAssembly.GetMelonAssemblyOfMember((MemberInfo)@delegate.GetMethodInfo(), (object)null);
					if (melonAssemblyOfMember != null)
					{
						Log.Error(string.Format("[Event: {0}] Delegate {1}, which is included in [{2}], raised an exception during execution.", "OnDamageTaken", @delegate, melonAssemblyOfMember.Assembly));
					}
					else
					{
						Log.Error(string.Format("[Event: {0}] Delegate {1} raised an exception during execution. This method is not part of a Melon, however, so your guess as to who did it is as good as mine.", "OnDamageTaken", @delegate));
					}
					Log.Error(msg);
				}
			}
		}

		private static void OnContextualDamageTaken(Player_Health @this, in ImmutableAttackInfo originalAttack, ref AttackInfo attack, in BodyPart originalPart, ref BodyPart part, EventPhase phase)
		{
			if (phase == EventPhase.After)
			{
				if (_isAboutToExecuteTAKEDAMAGEFromRecv.Count > 0 && (Object)(object)_isAboutToExecuteTAKEDAMAGEFromRecv.Peek() == (Object)(object)@this)
				{
					_isAboutToExecuteTAKEDAMAGEFromRecv.Pop();
				}
			}
			else if (_isAboutToExecuteTAKEDAMAGEFromRecv.Count > 0 && (Object)(object)_isAboutToExecuteTAKEDAMAGEFromRecv.Peek() == (Object)null)
			{
				Log.Error("DANGER: The stack to prevent damage function re-entry contained a destroyed Player_Health instance. This should be impossible (unless someone destroyed it while taking damage?) and might cause serious bugs / failures in this event.");
				_isAboutToExecuteTAKEDAMAGEFromRecv.Pop();
			}
			ExecuteAllDelegates(@this, attackInfoAndPartAvailable: true, in originalAttack, ref attack, in originalPart, ref part, phase);
			if (phase == EventPhase.Before)
			{
				_isAboutToExecuteTAKEDAMAGEFromRecv.Push(@this);
			}
		}

		private static void OnAmbiguousDamageTaken(Player_Health @this, in float originalAmount, ref float amount, EventPhase phase)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (_isAboutToExecuteTAKEDAMAGEFromRecv.Count <= 0 || !((Object)(object)_isAboutToExecuteTAKEDAMAGEFromRecv.Peek() == (Object)(object)@this))
			{
				AttackInfo attack = default(AttackInfo);
				BodyPart part = (BodyPart)0;
				ImmutableAttackInfo originalAttack = default(ImmutableAttackInfo);
				BodyPart originalPart = (BodyPart)0;
				ExecuteAllDelegates(@this, attackInfoAndPartAvailable: false, in originalAttack, ref attack, in originalPart, ref part, phase);
			}
		}
	}
}