Decompiled source of ErenTitanShifter v0.7.7

Mods/ErenTitanShifter.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BoneLib;
using BoneLib.BoneMenu;
using ErenTitanShifter;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.VRMK;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Eren Titan Shifter", "0.7.5", "DeanZSD", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ErenTitanShifter;

public sealed class Core : MelonMod
{
	private enum ErenForm
	{
		Other,
		Human,
		Titan
	}

	private sealed class FusionSpawnCallbackBridge
	{
		private readonly Core _owner;

		private readonly float _lifetimeSeconds;

		private readonly bool _becomingTitan;

		internal FusionSpawnCallbackBridge(Core owner, float lifetimeSeconds, bool becomingTitan)
		{
			_owner = owner;
			_lifetimeSeconds = lifetimeSeconds;
			_becomingTitan = becomingTitan;
		}

		internal Delegate CreateDelegate(Type delegateType, Type callbackInfoType)
		{
			try
			{
				MethodInfo method = typeof(FusionSpawnCallbackBridge).GetMethod("Handle", BindingFlags.Instance | BindingFlags.NonPublic).MakeGenericMethod(callbackInfoType);
				return Delegate.CreateDelegate(delegateType, this, method);
			}
			catch (Exception ex)
			{
				((MelonBase)_owner).LoggerInstance.Warning("Fusion bridge: callback delegate creation failed for " + delegateType?.FullName + ": " + ex.GetBaseException().Message);
				return null;
			}
		}

		private void Handle<T>(T info)
		{
			_owner.OnFusionNetworkFxSpawned(info, _lifetimeSeconds, _becomingTitan);
		}
	}

	private static class SfxSystem
	{
		private static Core _core;

		private static string _directory;

		private static readonly Dictionary<string, AudioClip> Fallback = new Dictionary<string, AudioClip>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, AudioClip> Custom = new Dictionary<string, AudioClip>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, DateTime> CustomStamp = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, DateTime> FailedStamp = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);

		internal static void Initialize(Core core)
		{
			_core = core;
			try
			{
				_directory = Path.Combine(MelonEnvironment.UserDataDirectory, "ErenTitanShifter", "SFX");
				Directory.CreateDirectory(_directory);
				WriteInstructions();
			}
			catch (Exception ex)
			{
				((MelonBase)core).LoggerInstance.Warning("Could not create ErenTitanShifter SFX folder: " + ex.Message);
			}
			BuildFallbackSounds();
		}

		internal static void Shutdown()
		{
			foreach (AudioClip value in Custom.Values)
			{
				try
				{
					if ((Object)(object)value != (Object)null)
					{
						Object.Destroy((Object)(object)value);
					}
				}
				catch
				{
				}
			}
			foreach (AudioClip value2 in Fallback.Values)
			{
				try
				{
					if ((Object)(object)value2 != (Object)null)
					{
						Object.Destroy((Object)(object)value2);
					}
				}
				catch
				{
				}
			}
			Custom.Clear();
			Fallback.Clear();
			CustomStamp.Clear();
			FailedStamp.Clear();
		}

		internal static void PlayWithFallback(string preferredSlot, string fallbackSlot, Vector3 position, float volume = 1f, float pitch = 1f)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (_core != null && _core._sfxEnabled.Value)
			{
				AudioClip clip = GetClip(preferredSlot);
				if ((Object)(object)clip != (Object)null)
				{
					PlayClip(preferredSlot, clip, position, volume, pitch);
				}
				else
				{
					Play(fallbackSlot, position, volume, pitch);
				}
			}
		}

		private static void PlayClip(string slot, AudioClip clip, Vector3 position, float volume, float pitch)
		{
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)clip == (Object)null || _core == null)
			{
				return;
			}
			float num = Mathf.Clamp01(volume * Mathf.Clamp(_core._sfxVolume.Value, 0f, 2f));
			pitch = Mathf.Clamp(pitch, 0.4f, 2f);
			try
			{
				switch ((slot ?? string.Empty).ToLowerInvariant())
				{
				case "roar":
					Audio.PlayAtPoint(clip, position, Audio.NPCVocals, num, pitch, 1f);
					break;
				case "steam":
					Audio.PlayAtPoint(clip, position, Audio.Ambience, num, pitch, 1f);
					break;
				case "bite":
				case "tease":
				case "charge":
				case "shift_tease":
				case "long_transform":
					Audio.PlayAtPoint(clip, position, Audio.HardInteraction, num, pitch, 1f);
					break;
				default:
					Audio.PlayAtPoint(clip, position, Audio.Impact, num, pitch, 1f);
					break;
				}
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Warning("SFX '" + slot + "' failed to play: " + ex.Message);
			}
		}

		internal static void Play(string slot, Vector3 position, float volume = 1f, float pitch = 1f)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (_core != null && _core._sfxEnabled.Value)
			{
				AudioClip clip = GetClip(slot);
				if (!((Object)(object)clip == (Object)null))
				{
					PlayClip(slot, clip, position, volume, pitch);
				}
			}
		}

		private static AudioClip GetClip(string slot)
		{
			if (string.IsNullOrWhiteSpace(slot))
			{
				return null;
			}
			if (!string.IsNullOrEmpty(_directory))
			{
				string text = Path.Combine(_directory, slot + ".wav");
				if (File.Exists(text))
				{
					DateTime dateTime;
					try
					{
						dateTime = File.GetLastWriteTimeUtc(text);
					}
					catch
					{
						dateTime = DateTime.MinValue;
					}
					if (Custom.TryGetValue(slot, out var value) && CustomStamp.TryGetValue(slot, out var value2) && value2 == dateTime && (Object)(object)value != (Object)null)
					{
						return value;
					}
					if (FailedStamp.TryGetValue(slot, out var value3) && value3 == dateTime)
					{
						if (!Fallback.TryGetValue(slot, out var value4))
						{
							return null;
						}
						return value4;
					}
					try
					{
						byte[] bytes = File.ReadAllBytes(text);
						AudioClip val = LoadWav(slot, bytes);
						if ((Object)(object)val != (Object)null)
						{
							if (Custom.TryGetValue(slot, out var value5) && (Object)(object)value5 != (Object)null)
							{
								try
								{
									Object.Destroy((Object)(object)value5);
								}
								catch
								{
								}
							}
							Custom[slot] = val;
							CustomStamp[slot] = dateTime;
							FailedStamp.Remove(slot);
							((MelonBase)_core).LoggerInstance.Msg("Loaded custom SFX: " + text);
							return val;
						}
						FailedStamp[slot] = dateTime;
						((MelonBase)_core).LoggerInstance.Warning("Custom SFX '" + text + "' could not be decoded. Falling back to procedural audio.");
					}
					catch (Exception ex)
					{
						FailedStamp[slot] = dateTime;
						((MelonBase)_core).LoggerInstance.Warning("Custom SFX '" + text + "' failed: " + ex.Message);
					}
				}
			}
			if (!Fallback.TryGetValue(slot, out var value6))
			{
				return null;
			}
			return value6;
		}

		private static void WriteInstructions()
		{
			if (!string.IsNullOrEmpty(_directory))
			{
				string path = Path.Combine(_directory, "README.txt");
				string contents = "EREN TITAN SHIFTER - CUSTOM SFX\n\nDrop PCM WAV files in this folder with these exact names:\n\nbite.wav      - finger bite / crunch\ncharge.wav    - electrical build-up\nblast.wav     - transformation thunder / impact\nsteam.wav     - steam burst / hiss\nroar.wav      - Titan arrival vocal/roar\nunshift.wav        - nape extraction / deshift cue\ntease.wav          - legacy small pre-shift electrical cue\nshift_tease.wav    - dedicated injury shift-tease cue; falls back to tease.wav\nlong_transform.wav - dedicated long injury-transformation buildup; falls back to charge.wav\n\nThe mod hot-reloads a file the next time that sound plays if its timestamp changed.\nCustom WAV tails are automatically faded to silence so they do not end with an abrupt cut.\nThe fade length is controlled by CustomWavFadeOutSeconds in MelonPreferences.cfg.\nFor the v0.4.4 optional slots, missing files fall back to the existing custom/base slot first:\n- shift_tease.wav -> tease.wav\n- long_transform.wav -> charge.wav\nOnly the older base slots retain their existing built-in procedural audio fallback.\n\nSupported WAV:\n- PCM 8 / 16 / 24 / 32-bit\n- IEEE float 32-bit\n- mono or stereo (other channel counts may also work)\n\nThis folder is local-client audio. Fusion avatar switching still works normally,\nbut remote players do not automatically receive these custom sounds.";
				File.WriteAllText(path, contents);
			}
		}

		private static AudioClip LoadWav(string name, byte[] bytes)
		{
			if (bytes == null || bytes.Length < 44)
			{
				return null;
			}
			if (ReadFourCC(bytes, 0) != "RIFF" || ReadFourCC(bytes, 8) != "WAVE")
			{
				return null;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = -1;
			int num6 = 0;
			int num7 = 12;
			while (num7 + 8 <= bytes.Length)
			{
				string text = ReadFourCC(bytes, num7);
				int num8 = BitConverter.ToInt32(bytes, num7 + 4);
				int num9 = num7 + 8;
				if (num8 < 0 || num9 > bytes.Length)
				{
					return null;
				}
				int num10 = Math.Min(num8, bytes.Length - num9);
				if (text == "fmt " && num10 >= 16)
				{
					num = BitConverter.ToInt16(bytes, num9);
					num2 = BitConverter.ToInt16(bytes, num9 + 2);
					num3 = BitConverter.ToInt32(bytes, num9 + 4);
					num4 = BitConverter.ToInt16(bytes, num9 + 14);
				}
				else if (text == "data")
				{
					num5 = num9;
					num6 = num10;
				}
				num7 = num9 + num8 + (num8 & 1);
				if (num7 < 0 || num7 > bytes.Length)
				{
					break;
				}
			}
			if (num2 <= 0 || num3 <= 0 || num4 <= 0 || num5 < 0 || num6 <= 0)
			{
				return null;
			}
			int num11 = (num4 + 7) / 8;
			if (num11 <= 0)
			{
				return null;
			}
			int num12 = num6 / num11 / num2;
			if (num12 <= 0)
			{
				return null;
			}
			float[] array = new float[num12 * num2];
			int num13 = num5;
			for (int i = 0; i < array.Length; i++)
			{
				if (num13 + num11 > num5 + num6)
				{
					break;
				}
				float num14;
				if (num == 3 && num4 == 32)
				{
					num14 = BitConverter.ToSingle(bytes, num13);
				}
				else
				{
					if (num != 1)
					{
						return null;
					}
					switch (num4)
					{
					case 8:
						num14 = (float)(bytes[num13] - 128) / 128f;
						break;
					case 16:
						num14 = (float)BitConverter.ToInt16(bytes, num13) / 32768f;
						break;
					case 24:
					{
						int num15 = bytes[num13] | (bytes[num13 + 1] << 8) | (bytes[num13 + 2] << 16);
						if ((num15 & 0x800000) != 0)
						{
							num15 |= -16777216;
						}
						num14 = (float)num15 / 8388608f;
						break;
					}
					case 32:
						num14 = (float)BitConverter.ToInt32(bytes, num13) / 2.1474836E+09f;
						break;
					default:
						return null;
					}
				}
				array[i] = Mathf.Clamp(num14, -1f, 1f);
				num13 += num11;
			}
			ApplyCustomWavTailFade(array, num12, num2, num3);
			AudioClip val = AudioClip.Create("ErenTitanShifter_Custom_" + name, num12, num2, num3, false);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0);
			((Object)val).hideFlags = (HideFlags)32;
			return val;
		}

		private static void ApplyCustomWavTailFade(float[] samples, int frames, int channels, int sampleRate)
		{
			if (_core == null || samples == null || frames <= 0 || channels <= 0 || sampleRate <= 0)
			{
				return;
			}
			float num = Mathf.Clamp(_core._customWavFadeOutSeconds.Value, 0f, 2f);
			if (num <= 0.0001f)
			{
				return;
			}
			float num2 = (float)frames / (float)sampleRate;
			int num3 = Mathf.Clamp(Mathf.RoundToInt(Mathf.Min(num, num2 * 0.35f) * (float)sampleRate), 1, frames);
			int num4 = frames - num3;
			for (int i = num4; i < frames; i++)
			{
				float num5 = ((num3 <= 1) ? 1f : ((float)(i - num4) / (float)(num3 - 1)));
				float num6 = num5 * num5 * (3f - 2f * num5);
				float num7 = 1f - num6;
				int num8 = i * channels;
				for (int j = 0; j < channels; j++)
				{
					int num9 = num8 + j;
					if (num9 >= 0 && num9 < samples.Length)
					{
						samples[num9] *= num7;
					}
				}
			}
		}

		private static string ReadFourCC(byte[] bytes, int offset)
		{
			if (bytes == null || offset < 0 || offset + 4 > bytes.Length)
			{
				return string.Empty;
			}
			return Encoding.ASCII.GetString(bytes, offset, 4);
		}

		private static void BuildFallbackSounds()
		{
			Fallback["bite"] = MakeBite();
			Fallback["charge"] = MakeCharge();
			Fallback["blast"] = MakeBlast();
			Fallback["steam"] = MakeSteam();
			Fallback["roar"] = MakeRoar();
			Fallback["unshift"] = MakeUnshift();
			Fallback["tease"] = MakeTease();
		}

		private static AudioClip MakeBite()
		{
			int num = Mathf.CeilToInt(13230.001f);
			float[] array = new float[num];
			Random random = new Random(1337);
			float num2 = 0f;
			float num3 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num4 = (float)i / 44100f;
				float num5 = (float)(random.NextDouble() * 2.0 - 1.0);
				num2 += (num5 - num2) * 0.16f;
				float num6 = num5 - num2;
				num3 += (num6 - num3) * 0.42f;
				float num7 = ((num4 < 0.02f) ? (1f - num4 / 0.02f) : 0f);
				float num8 = Mathf.Abs(num4 - 0.052f);
				float num9 = ((num8 < 0.014f) ? ((1f - num8 / 0.014f) * 0.7f) : 0f);
				float num10 = Mathf.Abs(num4 - 0.105f);
				float num11 = ((num10 < 0.02f) ? ((1f - num10 / 0.02f) * 0.42f) : 0f);
				float num12 = Mathf.Exp(-10.5f * num4);
				float num13 = (num2 * 0.85f + num3 * 0.34f) * num12 * (0.72f + 0.28f * Mathf.Abs(Mathf.Sin(num4 * 118f)));
				float num14 = (Mathf.Sin((float)Math.PI * 176f * num4) * 0.5f + Mathf.Sin((float)Math.PI * 286f * num4) * 0.2f) * Mathf.Exp(-22f * num4);
				float num15 = num5 * (num7 + num9 + num11) * 0.72f;
				array[i] = SoftClip(num13 + num14 + num15);
			}
			return CreateMonoClip("ETS_Bite_v4", 44100, array);
		}

		private static AudioClip MakeCharge()
		{
			int num = Mathf.CeilToInt(41895f);
			float[] array = new float[num];
			Random random = new Random(8821);
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num5 = Mathf.Clamp01((float)i / 44100f / 0.95f);
				float num6 = num5 * num5;
				float num7 = Mathf.Lerp(105f, 2100f, num6);
				num2 += (float)Math.PI * 2f * num7 / 44100f;
				float num8 = Mathf.Lerp(46f, 82f, num5);
				num3 += (float)Math.PI * 2f * num8 / 44100f;
				float num9 = (float)(random.NextDouble() * 2.0 - 1.0);
				num4 += (num9 - num4) * 0.075f;
				float num10 = num9 - num4;
				float num11 = Mathf.Lerp(0.0008f, 0.01f, num6);
				float num12 = ((random.NextDouble() < (double)num11) ? (num10 * Mathf.Lerp(0.55f, 1.55f, num5)) : 0f);
				float num13 = Mathf.SmoothStep(0.02f, 1f, num5);
				float num14 = 1f - Mathf.SmoothStep(0.86f, 1f, num5);
				float num15 = num13 * num14;
				float num16 = Mathf.Sin(num2) * 0.34f + Mathf.Sin(num2 * 0.503f + 0.8f) * 0.16f + Mathf.Sin(num2 * 1.997f) * 0.08f;
				float num17 = Mathf.Sin(num3) * Mathf.Lerp(0.1f, 0.34f, num5);
				float num18 = num10 * Mathf.Lerp(0.1f, 0.42f, num5);
				array[i] = SoftClip((num16 + num17 + num18 + num12) * num15);
			}
			return CreateMonoClip("ETS_Charge_v4", 44100, array);
		}

		private static AudioClip MakeBlast()
		{
			int num = Mathf.CeilToInt(72765f);
			float[] array = new float[num];
			Random random = new Random(44551);
			float num2 = 0f;
			float num3 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num4 = (float)i / 44100f;
				float num5 = (float)(random.NextDouble() * 2.0 - 1.0);
				num2 += (num5 - num2) * 0.075f;
				num3 += (num5 - num3) * 0.016f;
				float num6 = num2 - num3;
				float num7 = ((num4 < 0.075f) ? (1f - num4 / 0.075f) : 0f);
				float num8 = num5 * num7 * 2.2f + num6 * Mathf.Exp(-15f * num4) * 1.1f;
				float num9 = (Mathf.Sin((float)Math.PI * 74f * num4) * 0.92f + Mathf.Sin((float)Math.PI * 104f * num4) * 0.58f + Mathf.Sin((float)Math.PI * 158f * num4) * 0.22f) * Mathf.Exp(-2.15f * num4);
				float num10 = (num3 * 1.35f + num6 * 0.6f) * Mathf.Exp(-2.45f * num4);
				float num11 = num4 - 0.19f;
				float num12 = ((num11 > 0f) ? (Mathf.Sin((float)Math.PI * 92f * num11) * Mathf.Exp(-5.5f * num11) * 0.26f) : 0f);
				array[i] = SoftClip(num8 + num9 + num10 + num12);
			}
			return CreateMonoClip("ETS_Blast_v4", 44100, array);
		}

		private static AudioClip MakeSteam()
		{
			int num = Mathf.CeilToInt(103634.99f);
			float[] array = new float[num];
			Random random = new Random(9107);
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num5 = (float)i / 44100f;
				float num6 = Mathf.Clamp01(num5 / 2.35f);
				float num7 = (float)(random.NextDouble() * 2.0 - 1.0);
				num2 += (num7 - num2) * 0.25f;
				num3 += (num7 - num3) * 0.075f;
				num4 += (num7 - num4) * 0.012f;
				float num8 = (num7 - num2) * 0.9f + (num2 - num3) * 1.25f;
				float num9 = (num3 - num4) * 1.6f + num4 * 0.38f;
				float num10 = 0.72f + 0.28f * Mathf.Sin(33.300884f * num5 + Mathf.Sin(num5 * 3.1f));
				float num11 = Mathf.Clamp01(num5 / 0.045f);
				float num12 = 1f - Mathf.SmoothStep(0.6f, 1f, num6);
				float num13 = num11 * num12;
				float num14 = Mathf.Exp(-4.2f * num5) * num9 * 0.85f;
				float num15 = (num8 * 0.64f + num9 * 0.34f) * num10;
				array[i] = SoftClip((num14 + num15) * num13);
			}
			return CreateMonoClip("ETS_Steam_v4", 44100, array);
		}

		private static AudioClip MakeRoar()
		{
			int num = Mathf.CeilToInt(81585f);
			float[] array = new float[num];
			Random random = new Random(15000);
			float num2 = 0f;
			float num3 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num4 = (float)i / 44100f;
				float num5 = Mathf.Clamp01(num4 / 1.85f);
				float num6 = (float)(random.NextDouble() * 2.0 - 1.0);
				num2 += (num6 - num2) * 0.052f;
				float num7 = Mathf.Lerp(76f, 48f, Mathf.SmoothStep(0f, 1f, num5));
				float num8 = Mathf.Sin(38.32743f * num4) * 4.5f + Mathf.Sin(14.451326f * num4) * 2.2f;
				num3 += (float)Math.PI * 2f * Mathf.Max(24f, num7 + num8) / 44100f;
				float num9 = Mathf.Sin(num3) * 0.72f + Mathf.Sin(num3 * 1.51f + 0.35f) * 0.36f + Mathf.Sin(num3 * 2.08f + 1.1f) * 0.22f + Mathf.Sin(num3 * 2.73f + 0.52f) * 0.12f;
				float num10 = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01(num4 / 0.11f));
				float num11 = 1f - Mathf.SmoothStep(0.67f, 1f, num5);
				float num12 = 0.78f + 0.22f * Mathf.Sin(51.52212f * num4);
				array[i] = SoftClip((num9 * 0.5f + num2 * 0.95f) * num10 * num11 * num12);
			}
			return CreateMonoClip("ETS_Roar_v4", 44100, array);
		}

		private static AudioClip MakeUnshift()
		{
			int num = Mathf.CeilToInt(66150f);
			float[] array = new float[num];
			Random random = new Random(7119);
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num5 = (float)i / 44100f;
				float num6 = Mathf.Clamp01(num5 / 1.5f);
				float num7 = (float)(random.NextDouble() * 2.0 - 1.0);
				num2 += (num7 - num2) * 0.085f;
				float num8 = Mathf.Lerp(980f, 72f, Mathf.SmoothStep(0f, 1f, num6));
				num3 += (float)Math.PI * 2f * num8 / 44100f;
				num4 += (float)Math.PI * 2f * Mathf.Lerp(64f, 38f, num6) / 44100f;
				float num9 = Mathf.Sin(num3) * Mathf.Lerp(0.3f, 0.08f, num6) + Mathf.Sin(num3 * 0.49f) * 0.11f;
				float num10 = Mathf.Sin(num4) * Mathf.Exp(-2.8f * num5) * 0.42f;
				float num11 = num2 * (1f - Mathf.SmoothStep(0.62f, 1f, num6)) * 0.72f;
				float num12 = Mathf.Abs(num5 - 0.08f);
				float num13 = ((num12 < 0.03f) ? (num7 * (1f - num12 / 0.03f) * 0.72f) : 0f);
				float num14 = 1f - Mathf.SmoothStep(0.72f, 1f, num6);
				array[i] = SoftClip((num9 + num10 + num11 + num13) * num14);
			}
			return CreateMonoClip("ETS_Unshift_v4", 44100, array);
		}

		private static AudioClip MakeTease()
		{
			int num = Mathf.CeilToInt(15876.001f);
			float[] array = new float[num];
			Random random = new Random(91);
			float num2 = 0f;
			float num3 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num4 = (float)i / 44100f;
				float num5 = Mathf.Clamp01(num4 / 0.36f);
				float num6 = Mathf.Lerp(330f, 2600f, num5 * num5);
				num2 += (float)Math.PI * 2f * num6 / 44100f;
				float num7 = (float)(random.NextDouble() * 2.0 - 1.0);
				num3 += (num7 - num3) * 0.11f;
				float num8 = num7 - num3;
				float num9 = ((num4 < 0.022f) ? (1f - num4 / 0.022f) : 0f);
				float num10 = Mathf.Abs(num4 - 0.17f);
				float num11 = ((num10 < 0.018f) ? ((1f - num10 / 0.018f) * 0.65f) : 0f);
				float num12 = Mathf.Sin((float)Math.PI * num5);
				float num13 = Mathf.Sin(num2) * 0.36f + Mathf.Sin(num2 * 1.92f) * 0.1f;
				array[i] = SoftClip(num13 * num12 + num8 * (num9 + num11) * 0.6f);
			}
			return CreateMonoClip("ETS_Tease_v4", 44100, array);
		}

		private static AudioClip CreateMonoClip(string name, int sampleRate, float[] data)
		{
			if (data == null || data.Length == 0)
			{
				return null;
			}
			AudioClip val = AudioClip.Create(name, data.Length, 1, sampleRate, false);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			val.SetData(Il2CppStructArray<float>.op_Implicit(data), 0);
			((Object)val).hideFlags = (HideFlags)32;
			return val;
		}

		private static float SoftClip(float value)
		{
			return (float)Math.Tanh(value);
		}
	}

	private static class VfxSystem
	{
		private static Core _core;

		private static Material _lineMaterial;

		private static Material _particleMaterial;

		private static string _directory;

		private static string _activeBundlePath;

		private static DateTime _activeBundleStamp;

		private static AssetBundle _activeBundle;

		private static readonly Dictionary<string, GameObject> ExternalPrefabs = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> MissingSlots = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly List<GameObject> ActiveExternalInstances = new List<GameObject>();

		private static int HealingSteamPatternPhase;

		private static bool LoggedTitanHealingSteamLayout;

		private static bool Enabled
		{
			get
			{
				if (_core != null)
				{
					return _core._vfxEnabled.Value;
				}
				return false;
			}
		}

		private static float Intensity
		{
			get
			{
				if (_core != null)
				{
					return Mathf.Clamp(_core._vfxIntensity.Value, 0.25f, 2.5f);
				}
				return 1f;
			}
		}

		internal static void Initialize(Core core)
		{
			_core = core;
			HealingSteamPatternPhase = 0;
			LoggedTitanHealingSteamLayout = false;
			_lineMaterial = CreateMaterial("Universal Render Pipeline/Unlit", "Sprites/Default", "Unlit/Color");
			_particleMaterial = CreateMaterial("Universal Render Pipeline/Particles/Unlit", "Particles/Standard Unlit", "Sprites/Default");
			try
			{
				_directory = Path.Combine(MelonEnvironment.UserDataDirectory, "ErenTitanShifter", "VFX");
				Directory.CreateDirectory(_directory);
				WriteInstructions();
			}
			catch (Exception ex)
			{
				((MelonBase)core).LoggerInstance.Warning("Could not create ErenTitanShifter VFX folder: " + ex.Message);
			}
		}

		internal static void Shutdown()
		{
			for (int num = ActiveExternalInstances.Count - 1; num >= 0; num--)
			{
				try
				{
					GameObject val = ActiveExternalInstances[num];
					if ((Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)val);
					}
				}
				catch
				{
				}
			}
			ActiveExternalInstances.Clear();
			UnloadBundle();
			try
			{
				if ((Object)(object)_lineMaterial != (Object)null)
				{
					Object.Destroy((Object)(object)_lineMaterial);
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)_particleMaterial != (Object)null)
				{
					Object.Destroy((Object)(object)_particleMaterial);
				}
			}
			catch
			{
			}
			_lineMaterial = null;
			_particleMaterial = null;
			HealingSteamPatternPhase = 0;
			LoggedTitanHealingSteamLayout = false;
			_core = null;
		}

		internal static void SpawnFlash(Vector3 position, float intensity, float range, float lifetime)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				MelonCoroutines.Start(FlashRoutine(position, intensity * Intensity, range, lifetime));
			}
		}

		internal static void SpawnTeasePulse(Vector3 origin, float scale)
		{
			//IL_001a: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				scale = Mathf.Clamp(scale, 0.35f, 4f);
				SpawnLightningBurst(origin + Vector3.up * (0.12f * scale), 0.72f * scale, 3);
				SpawnSparkBurst(origin, 0.78f * scale, 18);
			}
		}

		internal static void SpawnHumanEmergeFallback(Vector3 origin, bool includeSteam)
		{
			//IL_002c: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0078: 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_000b: 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_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)
			if (Enabled)
			{
				if (includeSteam)
				{
					SpawnSteamBurst(origin + Vector3.up * 0.15f, 0.95f, 34);
				}
				SpawnSparkBurst(origin + Vector3.up * 0.3f, 0.7f, 12);
				SpawnLightningBurst(origin + Vector3.up * 0.22f, 0.55f, 2);
				SpawnFlash(origin + Vector3.up * 0.25f, 5.5f, 4f, 0.075f);
			}
		}

		internal static bool SpawnShiftFailureSteam(Vector3 origin, float scale)
		{
			//IL_0025: 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 (!Enabled)
			{
				return false;
			}
			scale = Mathf.Clamp(scale, 0.1f, 1.25f);
			if (SpawnExternalChild("titan_arrival", "Steam_Linger", origin, scale, 3f))
			{
				return true;
			}
			if (SpawnExternalChild("shift_blast", "Steam_Linger", origin, scale, 3f))
			{
				return true;
			}
			Core core = _core;
			if (core != null)
			{
				((MelonBase)core).LoggerInstance.Warning("Shift was blocked for lack of space, but no authored Steam_Linger child was available for the steam-only failure VFX.");
			}
			return false;
		}

		internal static void SpawnHealingSteamForCurrentForm(float baseScale, bool titanForm)
		{
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: 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_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: 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_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: 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_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || _core == null)
			{
				return;
			}
			baseScale = Mathf.Clamp(baseScale, 0.1f, 1.25f);
			if (!titanForm)
			{
				SpawnHealingSteam(_core.GetEffectAnchor(1f), baseScale);
				return;
			}
			if (!TryGetCurrentAvatarVisualBounds(out var combined) || ((Bounds)(ref combined)).size.y < 3f)
			{
				SpawnHealingSteam(((Object)(object)Player.Head != (Object)null) ? (Player.Head.position + Vector3.up * 0.55f) : _core.GetEffectAnchor(1f), Mathf.Clamp(baseScale * 2.25f, 0.25f, 2.75f));
				return;
			}
			float num = Mathf.Max(3f, ((Bounds)(ref combined)).size.y);
			float bodyRadius = Mathf.Clamp(Mathf.Max(((Bounds)(ref combined)).extents.x, ((Bounds)(ref combined)).extents.z) * 0.42f, num * 0.025f, num * 0.14f);
			float num2 = Mathf.Clamp(num / 4.5f, 1.75f, 3.5f);
			float num3 = Mathf.Clamp(baseScale * num2, 0.25f, 3f);
			Vector3 right = Vector3.right;
			Vector3 forward = Vector3.forward;
			try
			{
				if ((Object)(object)Player.Avatar != (Object)null)
				{
					Vector3 val = Vector3.ProjectOnPlane(((Component)Player.Avatar).transform.right, Vector3.up);
					right = ((Vector3)(ref val)).normalized;
					val = Vector3.ProjectOnPlane(((Component)Player.Avatar).transform.forward, Vector3.up);
					forward = ((Vector3)(ref val)).normalized;
				}
			}
			catch
			{
			}
			if (((Vector3)(ref right)).sqrMagnitude < 0.01f)
			{
				right = Vector3.right;
			}
			if (((Vector3)(ref forward)).sqrMagnitude < 0.01f)
			{
				forward = Vector3.forward;
			}
			int num4 = HealingSteamPatternPhase++ & 3;
			float num5 = (((num4 & 1) == 0) ? 1f : (-1f));
			float num6 = ((num4 < 2) ? 1f : (-1f));
			switch (num4)
			{
			case 0:
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.84f, 0.65f * num5, 0.1f * num6), num3);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.61f, -0.35f * num5, -0.55f * num6), num3);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.33f, 0.3f * num5, 0.15f * num6), num3 * 0.92f);
				break;
			case 1:
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.76f, -0.55f * num5, -0.45f * num6), num3);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.55f, 0.4f * num5, 0.4f * num6), num3);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.17f, -0.22f * num5, -0.1f * num6), num3 * 0.84f);
				break;
			case 2:
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.88f, -0.52f * num5, 0.05f * num6), num3 * 0.95f);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.67f, 0.3f * num5, 0.5f * num6), num3);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.36f, -0.34f * num5, -0.18f * num6), num3 * 0.92f);
				break;
			default:
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.8f, 0.6f * num5, -0.25f * num6), num3);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.59f, -0.3f * num5, 0.48f * num6), num3);
				SpawnHealingSteam(BodyPoint(combined, right, forward, bodyRadius, 0.19f, 0.2f * num5, 0.12f * num6), num3 * 0.84f);
				break;
			}
			if (!LoggedTitanHealingSteamLayout)
			{
				LoggedTitanHealingSteamLayout = true;
				((MelonBase)_core).LoggerInstance.Msg($"Titan healing steam distributed across body: rendererHeight={num:F2} m, emitterScale={num3:F2}, pattern=shoulders/ribs/legs (pelvis avoided).");
			}
		}

		private static Vector3 BodyPoint(Bounds bodyBounds, Vector3 right, Vector3 forward, float bodyRadius, float normalizedHeight, float lateral, float depth)
		{
			//IL_0002: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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)
			float num = Mathf.Lerp(((Bounds)(ref bodyBounds)).min.y, ((Bounds)(ref bodyBounds)).max.y, Mathf.Clamp01(normalizedHeight));
			return new Vector3(((Bounds)(ref bodyBounds)).center.x, num, ((Bounds)(ref bodyBounds)).center.z) + right * (bodyRadius * lateral) + forward * (bodyRadius * depth);
		}

		private static bool TryGetCurrentAvatarVisualBounds(out Bounds combined)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0083: 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)
			//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)
			combined = default(Bounds);
			try
			{
				if ((Object)(object)Player.Avatar == (Object)null)
				{
					return false;
				}
				Renderer[] array = Il2CppArrayBase<Renderer>.op_Implicit(((Component)Player.Avatar).gameObject.GetComponentsInChildren<Renderer>(true));
				bool flag = false;
				if (array == null)
				{
					return false;
				}
				foreach (Renderer val in array)
				{
					if ((Object)(object)val == (Object)null || !val.enabled)
					{
						continue;
					}
					Bounds bounds = val.bounds;
					if (!(((Bounds)(ref bounds)).size.y < 0.05f) && !(((Bounds)(ref bounds)).size.x + ((Bounds)(ref bounds)).size.z < 0.02f))
					{
						if (!flag)
						{
							combined = bounds;
							flag = true;
						}
						else
						{
							((Bounds)(ref combined)).Encapsulate(bounds);
						}
					}
				}
				return flag;
			}
			catch
			{
				return false;
			}
		}

		internal static void SpawnHealingSteam(Vector3 origin, float scale)
		{
			//IL_0024: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				scale = Mathf.Clamp(scale, 0.1f, 3f);
				if (!SpawnExternalChild("titan_arrival", "Steam_Linger", origin, scale, 2.5f) && !SpawnExternalChild("shift_blast", "Steam_Linger", origin, scale, 2.5f))
				{
					CreateParticles("ErenHealing_Steam", origin + Vector3.up * (0.1f * Mathf.Min(scale, 2f)), Mathf.Clamp(Mathf.RoundToInt(8f * Intensity), 4, 18), 1.15f, 0.12f * scale, 0.12f * scale, new Color(0.9f, 0.96f, 1f, 0.18f), -0.04f, 0.22f * scale);
				}
			}
		}

		private static bool SpawnExternalChild(string slot, string childName, Vector3 position, float effectScale, float destroyAfterSeconds)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || _core == null || !_core._externalVfxEnabled.Value)
			{
				return false;
			}
			if (!TryGetExternalPrefab(slot, out var prefab) || (Object)(object)prefab == (Object)null)
			{
				return false;
			}
			Transform val = FindChildRecursive(prefab.transform, childName);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			GameObject val2 = null;
			try
			{
				val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, position, Quaternion.identity);
				((Object)val2).name = "ErenHealing_" + childName;
				float num = Mathf.Max(0.01f, _core._externalVfxScaleMultiplier.Value);
				val2.transform.localScale = val.localScale * num * Mathf.Clamp(effectScale, 0.1f, 3f);
				ParticleSystem[] array = Il2CppArrayBase<ParticleSystem>.op_Implicit(val2.GetComponentsInChildren<ParticleSystem>(true));
				AudioSource[] array2 = Il2CppArrayBase<AudioSource>.op_Implicit(val2.GetComponentsInChildren<AudioSource>(true));
				for (int i = 0; i < array.Length; i++)
				{
					try
					{
						array[i].main.loop = false;
						array[i].Play(true);
					}
					catch
					{
					}
				}
				for (int j = 0; j < array2.Length; j++)
				{
					try
					{
						array2[j].Play();
					}
					catch
					{
					}
				}
				ActiveExternalInstances.Add(val2);
				MelonCoroutines.Start(ExternalVfxLifecycleRoutine(val2, "healing_steam", 1f, Mathf.Max(0.5f, destroyAfterSeconds), array, array2));
				return true;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					ActiveExternalInstances.Remove(val2);
					Object.Destroy((Object)(object)val2);
				}
				((MelonBase)_core).LoggerInstance.Warning("Healing steam child spawn failed: " + ex.Message);
				return false;
			}
		}

		private static Transform FindChildRecursive(Transform root, string childName)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (!((Object)(object)child == (Object)null))
				{
					if (string.Equals(((Object)child).name, childName, StringComparison.OrdinalIgnoreCase))
					{
						return child;
					}
					Transform val = FindChildRecursive(child, childName);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}

		internal static void SpawnLightningBurst(Vector3 origin, float scale, int count)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0055: 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_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)
			//IL_0068: 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)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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)
			//IL_008d: 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_009e: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				int num = Mathf.Clamp(Mathf.RoundToInt((float)count * Intensity), 1, 18);
				scale = Mathf.Clamp(scale, 0.35f, 8f);
				for (int i = 0; i < num; i++)
				{
					Vector3 insideUnitSphere = Random.insideUnitSphere;
					insideUnitSphere.y = Mathf.Abs(insideUnitSphere.y) * 0.35f;
					Vector3 start = origin + insideUnitSphere * (1.5f * scale) + Vector3.up * Random.Range(2.1f, 4.8f) * scale;
					Vector3 end = origin + Random.insideUnitSphere * (0.55f * scale);
					CreateLightning(start, end, scale, Random.Range(0.07f, 0.14f));
				}
			}
		}

		internal static void SpawnShockwave(Vector3 position, float scale)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				MelonCoroutines.Start(ShockwaveRoutine(position, Mathf.Clamp(scale, 0.35f, 8f)));
			}
		}

		internal static void SpawnSteamBurst(Vector3 position, float scale, int count)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				if (_core != null)
				{
					((MelonBase)_core).LoggerInstance.Warning($"PROCEDURAL steam fallback spawned: scale={scale:0.###}, count={count}");
				}
				scale = Mathf.Clamp(scale, 0.35f, 8f);
				int num = Mathf.Clamp(Mathf.RoundToInt((float)count * Intensity), 8, 220);
				CreateParticles("ErenShift_Steam", position, num, 1.55f + 0.11f * scale, 0.48f * scale, 0.2f * scale, new Color(0.94f, 0.97f, 1f, 0.3f), -0.12f, 0.42f * scale);
				CreateParticles("ErenShift_SteamMist", position + Vector3.up * (0.18f * scale), Mathf.Max(5, num / 3), 2.15f + 0.08f * scale, 0.22f * scale, 0.31f * scale, new Color(0.88f, 0.94f, 1f, 0.16f), -0.05f, 0.58f * scale);
			}
		}

		internal static void SpawnSparkBurst(Vector3 position, float scale, int count)
		{
			//IL_0035: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				scale = Mathf.Clamp(scale, 0.35f, 8f);
				int num = Mathf.Clamp(Mathf.RoundToInt((float)count * Intensity), 4, 120);
				CreateParticles("ErenShift_Sparks", position, num, 0.34f, 3f * scale, 0.032f * scale, new Color(1f, 0.67f, 0.16f, 1f), 0.28f, 0.18f * scale);
				CreateParticles("ErenShift_SparkCores", position, Mathf.Max(2, num / 5), 0.2f, 3.8f * scale, 0.017f * scale, new Color(1f, 0.96f, 0.78f, 1f), 0.34f, 0.13f * scale);
			}
		}

		internal static bool SpawnExternalWithFallback(string preferredSlot, string fallbackSlot, Vector3 position, float scale, float destroyAfterSeconds)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (SpawnExternal(preferredSlot, position, scale, destroyAfterSeconds))
			{
				return true;
			}
			return SpawnExternal(fallbackSlot, position, scale, destroyAfterSeconds);
		}

		internal static bool SpawnExternal(string slot, Vector3 position, float scale, float destroyAfterSeconds)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || _core == null || !_core._externalVfxEnabled.Value)
			{
				return false;
			}
			if (!TryGetExternalPrefab(slot, out var prefab) || (Object)(object)prefab == (Object)null)
			{
				return false;
			}
			GameObject val = null;
			try
			{
				val = Object.Instantiate<GameObject>(prefab, position, Quaternion.identity);
				((Object)val).name = ((Object)prefab).name;
				float num = Mathf.Max(0.01f, _core._externalVfxScaleMultiplier.Value);
				Vector3 localScale = val.transform.localScale;
				val.transform.localScale = localScale * num;
				ParticleSystem[] array = Il2CppArrayBase<ParticleSystem>.op_Implicit(val.GetComponentsInChildren<ParticleSystem>(true));
				AudioSource[] array2 = Il2CppArrayBase<AudioSource>.op_Implicit(val.GetComponentsInChildren<AudioSource>(true));
				((MelonBase)_core).LoggerInstance.Msg($"External VFX spawn '{slot}': authoredRootScale={localScale} userScale={num:0.###} anchorScale={scale:0.###} finalRootScale={val.transform.localScale}");
				for (int i = 0; i < array.Length; i++)
				{
					try
					{
						array[i].Play(true);
					}
					catch
					{
					}
				}
				for (int j = 0; j < array2.Length; j++)
				{
					try
					{
						array2[j].Play();
					}
					catch
					{
					}
				}
				ActiveExternalInstances.Add(val);
				MelonCoroutines.Start(ExternalVfxLifecycleRoutine(val, slot, scale, Mathf.Max(0.5f, destroyAfterSeconds), array, array2));
				return true;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					ActiveExternalInstances.Remove(val);
					Object.Destroy((Object)(object)val);
				}
				((MelonBase)_core).LoggerInstance.Warning("External VFX slot '" + slot + "' failed: " + ex.Message);
				return false;
			}
		}

		private static IEnumerator ExternalVfxLifecycleRoutine(GameObject spawned, string slot, float authoredScale, float requestedSafetySeconds, ParticleSystem[] particles, AudioSource[] audioSources)
		{
			if ((Object)(object)spawned == (Object)null)
			{
				yield break;
			}
			float startedAt = Time.unscaledTime;
			float num = ((_core == null) ? 0f : Mathf.Clamp(_core._externalVfxFollowMaxSeconds.Value, 0f, 10f));
			float maxEmission = ((_core == null) ? 4.5f : Mathf.Clamp(_core._externalVfxMaxEmissionSeconds.Value, 0.25f, 20f));
			float cleanupGrace = ((_core == null) ? 0.2f : Mathf.Clamp(_core._externalVfxCleanupGraceSeconds.Value, 0f, 3f));
			float hardCleanup = ((_core == null) ? 14f : Mathf.Clamp(_core._externalVfxHardCleanupSeconds.Value, 2f, 60f));
			hardCleanup = Mathf.Max(hardCleanup, requestedSafetySeconds + 2f);
			float num2 = EstimateAuthoredEmissionEnd(particles, maxEmission);
			float followUntil = Mathf.Min(num, num2);
			bool emissionStopped = false;
			while ((Object)(object)spawned != (Object)null)
			{
				float num3 = Time.unscaledTime - startedAt;
				if (!string.Equals(slot, "healing_steam", StringComparison.OrdinalIgnoreCase) && _core != null && _core._externalVfxFollowPlayer.Value && num3 <= followUntil)
				{
					try
					{
						spawned.transform.position = GetExternalFollowPosition(slot, authoredScale, spawned.transform.position);
					}
					catch
					{
					}
				}
				if (!emissionStopped && num3 >= maxEmission)
				{
					StopExternalEmission(particles);
					emissionStopped = true;
				}
				bool flag = AnyParticlesAlive(particles);
				bool flag2 = AnyAudioPlaying(audioSources);
				if (num3 > 0.15f && !flag && !flag2)
				{
					if (cleanupGrace > 0f)
					{
						yield return (object)new WaitForSeconds(cleanupGrace);
					}
					break;
				}
				if (num3 >= hardCleanup)
				{
					StopExternalEmission(particles);
					float drainUntil = Time.unscaledTime + Mathf.Clamp(cleanupGrace + 1.25f, 0.25f, 3f);
					while ((Object)(object)spawned != (Object)null && Time.unscaledTime < drainUntil && AnyParticlesAlive(particles))
					{
						yield return null;
					}
					break;
				}
				yield return null;
			}
			if ((Object)(object)spawned != (Object)null)
			{
				ActiveExternalInstances.Remove(spawned);
				Object.Destroy((Object)(object)spawned);
			}
		}

		private static float EstimateAuthoredEmissionEnd(ParticleSystem[] particles, float safetyCap)
		{
			float num = 0.25f;
			if (particles == null)
			{
				return num;
			}
			foreach (ParticleSystem val in particles)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					MainModule main = val.main;
					float num2 = Mathf.Max(0.05f, main.duration);
					if (main.loop)
					{
						num2 = Mathf.Min(num2, safetyCap);
					}
					num = Mathf.Max(num, num2);
				}
				catch
				{
				}
			}
			return Mathf.Clamp(num, 0.25f, safetyCap);
		}

		private static Vector3 GetExternalFollowPosition(string slot, float scale, Vector3 fallback)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (_core == null || (Object)(object)Player.Head == (Object)null)
			{
				return fallback;
			}
			if ((slot ?? string.Empty).ToLowerInvariant() == "shift_start")
			{
				return Player.Head.position;
			}
			float visualScale = Mathf.Max(1f, scale);
			if (_core._form == ErenForm.Human)
			{
				visualScale = 1f;
			}
			else if (_core._form == ErenForm.Titan)
			{
				visualScale = Mathf.Max(1f, _core._titanVfxScale.Value);
			}
			return _core.GetEffectAnchor(visualScale);
		}

		private static void StopExternalEmission(ParticleSystem[] particles)
		{
			if (particles == null)
			{
				return;
			}
			for (int i = 0; i < particles.Length; i++)
			{
				try
				{
					ParticleSystem val = particles[i];
					if ((Object)(object)val != (Object)null)
					{
						val.Stop(true, (ParticleSystemStopBehavior)1);
					}
				}
				catch
				{
				}
			}
		}

		private static bool AnyParticlesAlive(ParticleSystem[] particles)
		{
			if (particles == null || particles.Length == 0)
			{
				return false;
			}
			for (int i = 0; i < particles.Length; i++)
			{
				try
				{
					ParticleSystem val = particles[i];
					if ((Object)(object)val != (Object)null && val.IsAlive(true))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static bool AnyAudioPlaying(AudioSource[] audioSources)
		{
			if (audioSources == null || audioSources.Length == 0)
			{
				return false;
			}
			for (int i = 0; i < audioSources.Length; i++)
			{
				try
				{
					AudioSource val = audioSources[i];
					if ((Object)(object)val != (Object)null && val.isPlaying)
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static bool TryGetExternalPrefab(string slot, out GameObject prefab)
		{
			prefab = null;
			if (string.IsNullOrWhiteSpace(slot))
			{
				return false;
			}
			if (!TryEnsureBundleLoaded())
			{
				return false;
			}
			if (ExternalPrefabs.TryGetValue(slot, out prefab) && (Object)(object)prefab != (Object)null)
			{
				return true;
			}
			string[] prefabCandidates = GetPrefabCandidates(slot);
			for (int i = 0; i < prefabCandidates.Length; i++)
			{
				try
				{
					prefab = _activeBundle.LoadAsset<GameObject>(prefabCandidates[i]);
					if ((Object)(object)prefab != (Object)null)
					{
						ExternalPrefabs[slot] = prefab;
						((MelonBase)_core).LoggerInstance.Msg($"External VFX slot '{slot}' -> prefab '{prefabCandidates[i]}'");
						return true;
					}
				}
				catch
				{
				}
			}
			if (MissingSlots.Add(slot))
			{
				((MelonBase)_core).LoggerInstance.Warning("External VFX bundle loaded, but no prefab matched slot '" + slot + "'. See VFX/README.txt for accepted prefab names.");
			}
			return false;
		}

		private static bool TryEnsureBundleLoaded()
		{
			if (string.IsNullOrEmpty(_directory) || !Directory.Exists(_directory))
			{
				return false;
			}
			string text = FindBundlePath();
			if (string.IsNullOrEmpty(text) || !File.Exists(text))
			{
				return false;
			}
			DateTime dateTime;
			try
			{
				dateTime = File.GetLastWriteTimeUtc(text);
			}
			catch
			{
				dateTime = DateTime.MinValue;
			}
			if ((Object)(object)_activeBundle != (Object)null && string.Equals(_activeBundlePath, text, StringComparison.OrdinalIgnoreCase) && _activeBundleStamp == dateTime)
			{
				return true;
			}
			UnloadBundle();
			try
			{
				_activeBundle = AssetBundle.LoadFromFile(text);
				if ((Object)(object)_activeBundle == (Object)null)
				{
					((MelonBase)_core).LoggerInstance.Warning("Failed to load external VFX bundle: " + text);
					return false;
				}
				_activeBundlePath = text;
				_activeBundleStamp = dateTime;
				MissingSlots.Clear();
				((MelonBase)_core).LoggerInstance.Msg("Loaded external VFX bundle: " + text);
				return true;
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Warning("External VFX bundle load failed: " + ex.Message);
				UnloadBundle();
				return false;
			}
		}

		private static void UnloadBundle()
		{
			ExternalPrefabs.Clear();
			MissingSlots.Clear();
			if ((Object)(object)_activeBundle != (Object)null)
			{
				try
				{
					_activeBundle.Unload(false);
				}
				catch
				{
				}
			}
			_activeBundle = null;
			_activeBundlePath = null;
			_activeBundleStamp = DateTime.MinValue;
		}

		private static string FindBundlePath()
		{
			try
			{
				string[] array = new string[4]
				{
					Path.Combine(_directory, "erentitanfx.bundle"),
					Path.Combine(_directory, "erentitanfx"),
					Path.Combine(_directory, "ErenTitanFX.bundle"),
					Path.Combine(_directory, "ErenTitanFX")
				};
				for (int i = 0; i < array.Length; i++)
				{
					if (File.Exists(array[i]))
					{
						return array[i];
					}
				}
				string[] files = Directory.GetFiles(_directory);
				foreach (string text in files)
				{
					switch (Path.GetExtension(text).ToLowerInvariant())
					{
					case ".manifest":
					case ".meta":
					case ".txt":
						continue;
					}
					return text;
				}
			}
			catch
			{
			}
			return null;
		}

		private static string[] GetPrefabCandidates(string slot)
		{
			return (slot ?? string.Empty).ToLowerInvariant() switch
			{
				"shift_start" => new string[4] { "Eren_ShiftStartFX", "ShiftStartFX", "Eren_BiteFX", "BiteFX" }, 
				"shift_charge" => new string[4] { "Eren_ShiftChargeFX", "ShiftChargeFX", "Eren_ChargeFX", "ChargeFX" }, 
				"shift_blast" => new string[4] { "Eren_ShiftBlastFX", "ShiftBlastFX", "Eren_ShiftFX", "ShiftFX" }, 
				"titan_arrival" => new string[4] { "Eren_TitanArrivalFX", "TitanArrivalFX", "Eren_ArrivalFX", "ArrivalFX" }, 
				"unshift" => new string[4] { "Eren_UnshiftFX", "UnshiftFX", "Eren_TitanExitFX", "TitanExitFX" }, 
				"human_emerge" => new string[4] { "Eren_HumanEmergeFX", "HumanEmergeFX", "Eren_PostUnshiftFX", "PostUnshiftFX" }, 
				"tease" => new string[4] { "Eren_TeaseFX", "TeaseFX", "Eren_PreshiftFX", "PreshiftFX" }, 
				"shift_tease" => new string[2] { "Eren_ShiftTeaseFX", "ShiftTeaseFX" }, 
				"long_transform" => new string[4] { "Eren_LongTransformFX", "LongTransformFX", "Eren_InjuryTransformFX", "InjuryTransformFX" }, 
				_ => new string[1] { slot }, 
			};
		}

		private static void WriteInstructions()
		{
			if (!string.IsNullOrEmpty(_directory))
			{
				string path = Path.Combine(_directory, "README.txt");
				string contents = "EREN TITAN SHIFTER - CUSTOM VFX BUNDLE\n\nDrop a Unity AssetBundle in this folder. Recommended filenames:\n- erentitanfx.bundle\n- erentitanfx\n\nThe mod will hot-reload a changed bundle the next time a shift effect tries to play.\n\nv0.2.4 lifecycle behavior:\n- The prefab emitter root follows Eren/Titan while it is actively emitting.\n- Keep smoke Particle Systems in Simulation Space = World so old steam stays behind naturally.\n- Cleanup waits for particles and prefab audio to finish instead of deleting visible smoke on a fixed timer.\n- Color over Lifetime should fade alpha to 0 for the smoothest visual tail.\n\nRecommended prefab slots inside the bundle:\n\nEren_ShiftStartFX      or ShiftStartFX\n    Played right as the bite/injury shift begins.\n\nEren_ShiftChargeFX     or ShiftChargeFX\n    Played during the electrical buildup before the main blast.\n\nEren_ShiftBlastFX      or ShiftBlastFX\n    Main transformation steam / smoke / debris blast.\n    Also accepts Eren_ShiftFX or ShiftFX.\n\nEren_TitanArrivalFX    or TitanArrivalFX\n    Played immediately after the Titan avatar appears.\n\nEren_UnshiftFX         or UnshiftFX\n    Main Titan steam/extraction effect during deshift.\n\nEren_HumanEmergeFX     or HumanEmergeFX\n    Small residual effect after Human Eren reappears.\n\nEren_TeaseFX           or TeaseFX\n    Legacy injury-shift tease prefab.\n\nEren_ShiftTeaseFX      or ShiftTeaseFX\n    Dedicated v0.4.4 injury shift-tease prefab.\n    If missing: falls back to Eren_TeaseFX/TeaseFX, then Eren_ShiftChargeFX/ShiftChargeFX.\n\nEren_LongTransformFX   or LongTransformFX\nEren_InjuryTransformFX or InjuryTransformFX\n    Dedicated long injury-transformation buildup prefab.\n    If missing: the buildup reuses your existing tease/charge authored prefabs.\n\nPrefab authoring rules:\n- Use particle systems, meshes, lights, and audio sources.\n- Make the effect self-contained and safe to instantiate at world origin.\n- Particle systems should Play On Awake, but the mod also forces Play() on spawn.\n- AudioSources inside the prefab will also be played on spawn.\n- Avoid gameplay scripts or scene dependencies.\n\nThis bundle is LOCAL to your client. Other Fusion players will still see your avatar changes,\nbut they will not automatically receive your local external VFX bundle.";
				File.WriteAllText(path, contents);
			}
		}

		private static IEnumerator FlashRoutine(Vector3 position, float intensity, float range, float lifetime)
		{
			//IL_0007: 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)
			GameObject flash = null;
			try
			{
				flash = new GameObject("ErenShift_Flash");
				flash.transform.position = position;
				Light light = flash.AddComponent<Light>();
				light.type = (LightType)2;
				light.color = new Color(1f, 0.9f, 0.68f, 1f);
				light.range = Mathf.Max(1f, range);
				light.intensity = Mathf.Max(0f, intensity);
				float started = Time.unscaledTime;
				float duration = Mathf.Max(0.03f, lifetime);
				while (Time.unscaledTime - started < duration)
				{
					float num = Mathf.Clamp01((Time.unscaledTime - started) / duration);
					light.intensity = intensity * (1f - num) * (1f - num);
					yield return null;
				}
			}
			finally
			{
				if ((Object)(object)flash != (Object)null)
				{
					Object.Destroy((Object)(object)flash);
				}
			}
		}

		private static void CreateLightning(Vector3 start, Vector3 end, float scale, float lifetime)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ErenShift_Lightning");
			int num = Mathf.Clamp(Mathf.RoundToInt(7f + scale * 1.5f), 7, 16);
			Vector3[] array = (Vector3[])(object)new Vector3[num + 1];
			Vector3 val2 = end - start;
			Vector3 val3 = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val2)).normalized : Vector3.up);
			Vector3 val4 = Vector3.Cross(val3, Vector3.up);
			if (((Vector3)(ref val4)).sqrMagnitude < 0.01f)
			{
				val4 = Vector3.Cross(val3, Vector3.right);
			}
			((Vector3)(ref val4)).Normalize();
			Vector3 val5 = Vector3.Cross(val3, val4);
			Vector3 normalized = ((Vector3)(ref val5)).normalized;
			float num2 = 0.11f * scale;
			for (int i = 0; i <= num; i++)
			{
				float num3 = (float)i / (float)num;
				Vector3 val6 = Vector3.Lerp(start, end, num3);
				float num4 = Mathf.Sin((float)Math.PI * num3);
				Vector3 val7 = (val4 * Random.Range(-1f, 1f) + normalized * Random.Range(-1f, 1f)) * num2 * num4;
				array[i] = val6 + val7;
			}
			LineRenderer glow = CreateLineLayer(val.transform, "Glow", array, 0.105f * Mathf.Sqrt(scale), new Color(1f, 0.58f, 0.18f, 0.36f));
			LineRenderer core = CreateLineLayer(val.transform, "Core", array, 0.028f * Mathf.Sqrt(scale), new Color(1f, 0.96f, 0.78f, 1f));
			MelonCoroutines.Start(LightningLifeRoutine(val, glow, core, lifetime));
		}

		private static LineRenderer CreateLineLayer(Transform parent, string name, Vector3[] points, float width, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			LineRenderer val2 = val.AddComponent<LineRenderer>();
			val2.useWorldSpace = true;
			val2.positionCount = points.Length;
			val2.SetPositions(Il2CppStructArray<Vector3>.op_Implicit(points));
			val2.startWidth = width;
			val2.endWidth = width * 0.55f;
			val2.numCapVertices = 2;
			val2.numCornerVertices = 1;
			val2.startColor = color;
			val2.endColor = new Color(color.r, color.g, color.b, color.a * 0.65f);
			if ((Object)(object)_lineMaterial != (Object)null)
			{
				((Renderer)val2).material = _lineMaterial;
			}
			return val2;
		}

		private static IEnumerator LightningLifeRoutine(GameObject root, LineRenderer glow, LineRenderer core, float lifetime)
		{
			float duration = Mathf.Max(0.04f, lifetime);
			float started = Time.unscaledTime;
			while ((Object)(object)root != (Object)null && Time.unscaledTime - started < duration)
			{
				float num = Mathf.Clamp01((Time.unscaledTime - started) / duration);
				float num2 = ((Random.value > 0.18f) ? 1f : 0.25f);
				float num3 = (1f - num) * num2;
				if ((Object)(object)glow != (Object)null)
				{
					glow.startColor = new Color(1f, 0.58f, 0.18f, 0.36f * num3);
					glow.endColor = new Color(1f, 0.46f, 0.08f, 0.2f * num3);
				}
				if ((Object)(object)core != (Object)null)
				{
					core.startColor = new Color(1f, 0.96f, 0.78f, num3);
					core.endColor = new Color(1f, 0.82f, 0.42f, 0.72f * num3);
				}
				yield return null;
			}
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
			}
		}

		private static IEnumerator ShockwaveRoutine(Vector3 position, float scale)
		{
			//IL_0007: 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)
			GameObject root = new GameObject("ErenShift_Shockwave");
			LineRenderer line = root.AddComponent<LineRenderer>();
			line.useWorldSpace = true;
			line.loop = true;
			line.positionCount = 49;
			line.numCapVertices = 2;
			if ((Object)(object)_lineMaterial != (Object)null)
			{
				((Renderer)line).material = _lineMaterial;
			}
			float duration = 0.42f;
			float started = Time.unscaledTime;
			float maxRadius = 3.8f * scale;
			while (Time.unscaledTime - started < duration)
			{
				float num = Mathf.Clamp01((Time.unscaledTime - started) / duration);
				float num2 = 1f - (1f - num) * (1f - num);
				float num3 = Mathf.Lerp(0.18f * scale, maxRadius, num2);
				float num4 = (1f - num) * 0.86f;
				for (int i = 0; i < 49; i++)
				{
					float num5 = (float)i / 48f * (float)Math.PI * 2f;
					line.SetPosition(i, position + new Vector3(Mathf.Cos(num5) * num3, 0f, Mathf.Sin(num5) * num3));
				}
				float endWidth = (line.startWidth = Mathf.Lerp(0.11f * scale, 0.025f * scale, num));
				line.endWidth = endWidth;
				line.startColor = new Color(1f, 0.84f, 0.52f, num4);
				line.endColor = new Color(1f, 0.55f, 0.16f, num4 * 0.65f);
				yield return null;
			}
			Object.Destroy((Object)(object)root);
		}

		private static void CreateParticles(string name, Vector3 position, int count, float lifetime, float speed, float size, Color color, float gravityModifier, float radius)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = null;
			try
			{
				val = new GameObject(name);
				val.transform.position = position;
				ParticleSystem obj = val.AddComponent<ParticleSystem>();
				MainModule main = obj.main;
				main.loop = false;
				main.playOnAwake = false;
				main.simulationSpace = (ParticleSystemSimulationSpace)1;
				float num = Mathf.Max(0.08f, lifetime);
				float num2 = Mathf.Max(0f, speed);
				float num3 = Mathf.Max(0.01f, size);
				main.startLifetime = new MinMaxCurve(num * 0.68f, num * 1.18f);
				main.startSpeed = new MinMaxCurve(num2 * 0.58f, num2 * 1.24f);
				main.startSize = new MinMaxCurve(num3 * 0.62f, num3 * 1.42f);
				main.startRotation = new MinMaxCurve(0f, (float)Math.PI * 2f);
				main.startColor = MinMaxGradient.op_Implicit(color);
				main.gravityModifier = MinMaxCurve.op_Implicit(gravityModifier);
				main.maxParticles = Mathf.Max(16, count + 8);
				obj.emission.enabled = false;
				ShapeModule shape = obj.shape;
				shape.shapeType = (ParticleSystemShapeType)0;
				shape.radius = Mathf.Max(0.02f, radius);
				ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					if ((Object)(object)_particleMaterial != (Object)null)
					{
						((Renderer)component).material = _particleMaterial;
					}
					component.renderMode = (ParticleSystemRenderMode)0;
					if (name.IndexOf("Steam", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						component.minParticleSize = 0f;
						component.maxParticleSize = 0.42f;
					}
				}
				obj.Emit(count);
				Object.Destroy((Object)(object)val, num * 1.25f + 0.85f);
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				if (_core != null)
				{
					((MelonBase)_core).LoggerInstance.Warning("Particle VFX '" + name + "' failed: " + ex.Message);
				}
			}
		}

		private static Material CreateMaterial(params string[] shaderNames)
		{
			//IL_001d: 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)
			//IL_002c: Expected O, but got Unknown
			foreach (string text in shaderNames)
			{
				try
				{
					Shader val = Shader.Find(text);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					return new Material(val)
					{
						hideFlags = (HideFlags)32
					};
				}
				catch
				{
				}
			}
			return null;
		}
	}

	private const string ModVersion = "0.7.5";

	private const string HumanBarcode = "DeanZSD.ErenTitanShifting.Avatar.ErenShiftable";

	private const string TitanBarcode = "DeanZSD.ErenTitanShifting.Avatar.AttackTitan";

	private const string DefaultFusionShiftFxSpawnableBarcode = "DeanZSD.ErenTitanShifting.Spawnable.ErenShiftFX";

	private const string DefaultFusionUnshiftFxSpawnableBarcode = "DeanZSD.ErenTitanShifting.Spawnable.ErenUnshiftFX";

	internal const float FusionShiftStartTime = 0f;

	internal const float FusionShiftChargeTime = 0.055f;

	internal const float FusionShiftIntensifyTime = 0.14f;

	internal const float FusionShiftBlastTime = 0.225f;

	private ErenForm _form;

	private bool _changingForm;

	private float _changeStartedAt;

	private string _pendingAvatarBarcode = string.Empty;

	private bool _avatarSwapCallbackReceived;

	private bool _avatarSwapCallbackSuccess;

	private string _avatarSwapCallbackBarcode = string.Empty;

	private bool _avatarWaitReachedTarget;

	private float _biteHold;

	private float _shiftPressure;

	private float _titanStability = 100f;

	private float _titanStabilityGraceUntil = -999f;

	private bool _titanStabilityGraceLoggedDamage;

	private bool _titanDeathEjectPending;

	private float _lastTitanDeathEjectAttemptAt = -999f;

	private float _lastObservedTitanHealth = -1f;

	private float _titanNativeMaxHealth = -1f;

	private float _titanAppliedMaxHealth = -1f;

	private float _lastTitanHealthMultiplierCheckAt = -999f;

	private const float TitanDeathEjectThresholdFraction = 0.01f;

	private const float TitanDeathEjectHumanHealthFraction = 0.2f;

	private float _lastDamageAt = -999f;

	private float _lastDamageRollAt = -999f;

	private float _lastStateCheckAt = -999f;

	private float _lastSteamHealingFxAt = -999f;

	private bool _biteLatched;

	private float _leftNapeGraceUntil = -999f;

	private float _rightNapeGraceUntil = -999f;

	private bool _leftNapeZoneActive;

	private bool _rightNapeZoneActive;

	private float _lastNapeDebugAt = -999f;

	private bool _leftNapeArmed;

	private bool _rightNapeArmed;

	private float _leftNapeArmStartedAt = -999f;

	private float _rightNapeArmStartedAt = -999f;

	private float _leftNapeHold;

	private float _rightNapeHold;

	private bool _leftNapePrevTrigger;

	private bool _rightNapePrevTrigger;

	private int _fusionDiagnosticRequestSerial;

	private const float TitanClearanceLegacyEnvelopeHeight = 15f;

	private const float TitanClearanceReferenceHeight = 5.4864f;

	private const float TitanClearanceGeometryScale = 0.36576f;

	private const float TitanClearanceSearchStep = 0.35f;

	private const int TitanClearanceDirections = 16;

	private const float TitanClearanceSafetyMinScale = 1f;

	private const float TitanClearanceSafetyMaxScale = 3f;

	private const float TitanClearanceSafetyPadding = 1.06f;

	private const float TitanClearanceMaxGroundSlope = 40f;

	private const float TitanClearanceMaxRelocationGroundDelta = 0.45f;

	private float _titanClearanceLearnedScale = 1f;

	private float _nextClearanceFailureFxAt = -999f;

	private bool _cancelNextFusionShiftFxSpawnForSafety;

	private bool _activeFusionShiftFxValid;

	private ushort _activeFusionShiftFxEntityId;

	private MelonPreferences_Category _prefs;

	private Page _boneMenuRoot;

	private MelonPreferences_Entry<bool> _injuryShiftEnabled;

	private MelonPreferences_Entry<bool> _requireEmptyHand;

	private MelonPreferences_Entry<float> _mouthRadius;

	private MelonPreferences_Entry<float> _biteHoldSeconds;

	private MelonPreferences_Entry<float> _napeHoldSeconds;

	private MelonPreferences_Entry<float> _napeBoxMinSide;

	private MelonPreferences_Entry<float> _napeBoxMaxSide;

	private MelonPreferences_Entry<float> _napeBoxBackStart;

	private MelonPreferences_Entry<float> _napeBoxBackEnd;

	private MelonPreferences_Entry<float> _napeBoxDown;

	private MelonPreferences_Entry<float> _napeBoxUp;

	private MelonPreferences_Entry<float> _napeTrackingGrace;

	private MelonPreferences_Entry<bool> _requireEmptyHandForUnshift;

	private MelonPreferences_Entry<bool> _napeDebugLogging;

	private MelonPreferences_Entry<bool> _unshiftBlockWhileHoldingObject;

	private MelonPreferences_Entry<float> _unshiftArmSeconds;

	private MelonPreferences_Entry<float> _unshiftSafeHoldSeconds;

	private MelonPreferences_Entry<float> _pressurePerDamage;

	private MelonPreferences_Entry<float> _pressureDecayPerSecond;

	private MelonPreferences_Entry<float> _pressureDecayDelay;

	private MelonPreferences_Entry<float> _injuryShiftThreshold;

	private MelonPreferences_Entry<float> _maxInjuryShiftChance;

	private MelonPreferences_Entry<float> _teaseChanceAtMaxPressure;

	private MelonPreferences_Entry<float> _forceShiftChancePerInjury;

	private MelonPreferences_Entry<float> _forceShiftMinDamage;

	private MelonPreferences_Entry<bool> _injuryCinematicShiftEnabled;

	private MelonPreferences_Entry<float> _injuryCinematicDuration;

	private MelonPreferences_Entry<bool> _steamHealingEnabled;

	private MelonPreferences_Entry<float> _steamHealingRate;

	private MelonPreferences_Entry<float> _steamHealingDelay;

	private MelonPreferences_Entry<float> _steamHealingVfxScale;

	private MelonPreferences_Entry<float> _steamHealingVfxInterval;

	private MelonPreferences_Entry<bool> _shiftRestoresFullHealth;

	private MelonPreferences_Entry<float> _titanHealthMultiplier;

	private MelonPreferences_Entry<bool> _titanClearanceCheckEnabled;

	private MelonPreferences_Entry<float> _titanClearanceSearchRadius;

	private MelonPreferences_Entry<float> _titanStabilityDamageMultiplier;

	private MelonPreferences_Entry<float> _titanStabilityGraceSeconds;

	private MelonPreferences_Entry<bool> _localFlashEnabled;

	private MelonPreferences_Entry<bool> _debugKeysEnabled;

	private MelonPreferences_Entry<bool> _titanRigRefreshEnabled;

	private MelonPreferences_Entry<bool> _titanRigRefreshHardReset;

	private MelonPreferences_Entry<float> _titanRigRefreshDelay;

	private MelonPreferences_Entry<float> _titanRigRefreshShutdownSeconds;

	private MelonPreferences_Entry<bool> _titanHandlingAssistEnabled;

	private MelonPreferences_Entry<float> _titanAgilityTarget;

	private MelonPreferences_Entry<float> _titanArmResponseMultiplier;

	private bool _titanArmBaselineValid;

	private float _titanArmBaselineLeft = -1f;

	private float _titanArmBaselineRight = -1f;

	private int _titanHandlingStatPassSerial;

	private float _lastTitanHandlingStatPassAt = -999f;

	private bool _impactRagdollWasLocked;

	private bool _impactRagdollRecoveryScheduled;

	private MelonPreferences_Entry<bool> _vfxEnabled;

	private MelonPreferences_Entry<bool> _sfxEnabled;

	private MelonPreferences_Entry<float> _vfxIntensity;

	private MelonPreferences_Entry<float> _sfxVolume;

	private MelonPreferences_Entry<float> _customWavFadeOutSeconds;

	private MelonPreferences_Entry<float> _titanVfxScale;

	private MelonPreferences_Entry<float> _shiftSwapDelay;

	private MelonPreferences_Entry<float> _unshiftSwapDelay;

	private MelonPreferences_Entry<bool> _titanArrivalRoar;

	private MelonPreferences_Entry<bool> _externalVfxEnabled;

	private MelonPreferences_Entry<float> _externalVfxScaleMultiplier;

	private MelonPreferences_Entry<bool> _externalVfxReplaceProceduralSteam;

	private MelonPreferences_Entry<bool> _externalVfxFollowPlayer;

	private MelonPreferences_Entry<float> _externalVfxFollowMaxSeconds;

	private MelonPreferences_Entry<float> _externalVfxMaxEmissionSeconds;

	private MelonPreferences_Entry<float> _externalVfxCleanupGraceSeconds;

	private MelonPreferences_Entry<float> _externalVfxHardCleanupSeconds;

	private MelonPreferences_Entry<bool> _fusionBridgeEnabled;

	private MelonPreferences_Entry<bool> _fusionOnlyWhenConnected;

	private MelonPreferences_Entry<string> _fusionShiftFxSpawnableBarcode;

	private MelonPreferences_Entry<string> _fusionUnshiftFxSpawnableBarcode;

	private MelonPreferences_Entry<float> _fusionShiftFxLifetimeSeconds;

	private MelonPreferences_Entry<float> _fusionUnshiftFxLifetimeSeconds;

	private Assembly _fusionAssembly;

	private Type _fusionNetworkAssetSpawnerType;

	private Type _fusionSpawnRequestInfoType;

	private Type _fusionDespawnRequestInfoType;

	private MethodInfo _fusionSpawnMethod;

	private MethodInfo _fusionDespawnMethod;

	internal static Core Instance { get; private set; }

	public override void OnInitializeMelon()
	{
		Instance = this;
		SetupPreferences();
		SetupBoneMenu();
		SfxSystem.Initialize(this);
		VfxSystem.Initialize(this);
		Hooking.OnLevelLoaded += OnLevelLoaded;
		Hooking.OnSwitchAvatarPostfix += OnAvatarSwitched;
		Hooking.OnPlayerDamageReceived += OnPlayerDamaged;
		((MelonBase)this).LoggerInstance.Msg("Eren Titan Shifter v0.7.5 initialized.");
		((MelonBase)this).LoggerInstance.Msg("Human: DeanZSD.ErenTitanShifting.Avatar.ErenShiftable");
		((MelonBase)this).LoggerInstance.Msg("Titan: DeanZSD.ErenTitanShifting.Avatar.AttackTitan");
		((MelonBase)this).LoggerInstance.Msg("v0.7.5: stable-neck post-shift PhysicsRig refresh remains enabled; ImpactRagdoll ownership is respected during avatar swaps.");
		((MelonBase)this).LoggerInstance.Msg("v0.7.5 middle-ground handling: native mass/strength/speed, modest agility target, light arm response; no leg/torso/neck drive patches.");
		((MelonBase)this).LoggerInstance.Msg("v0.7.5 Titan durability: configurable max-health multiplier, default x3.0; Human health is untouched.");
	}

	public override void OnDeinitializeMelon()
	{
		Hooking.OnLevelLoaded -= OnLevelLoaded;
		Hooking.OnSwitchAvatarPostfix -= OnAvatarSwitched;
		Hooking.OnPlayerDamageReceived -= OnPlayerDamaged;
		VfxSystem.Shutdown();
		SfxSystem.Shutdown();
	}

	public override void OnUpdate()
	{
		if ((Object)(object)Player.RigManager == (Object)null)
		{
			return;
		}
		if (Time.unscaledTime - _lastStateCheckAt >= 0.2f)
		{
			_lastStateCheckAt = Time.unscaledTime;
			RefreshFormFromCurrentAvatar();
		}
		UpdateImpactRagdollInterop();
		MaintainTitanHealthMultiplier();
		UpdateTitanDeathEjection();
		if (_changingForm)
		{
			float num = 8f;
			if (_injuryCinematicShiftEnabled != null && _injuryCinematicShiftEnabled.Value)
			{
				num = Mathf.Max(num, Mathf.Clamp(_injuryCinematicDuration.Value, 0.8f, 6f) + 7f);
			}
			if (Time.unscaledTime - _changeStartedAt > num)
			{
				((MelonBase)this).LoggerInstance.Warning("Avatar change timed out. Unlocking shifter state.");
				_changingForm = false;
				_pendingAvatarBarcode = string.Empty;
				RefreshFormFromCurrentAvatar();
			}
		}
		else
		{
			if ((Object)(object)Player.Head == (Object)null || !Player.HandsExist || !Player.ControllersExist)
			{
				return;
			}
			UpdateSteamHealing();
			DecayShiftPressure();
			if (_debugKeysEnabled.Value)
			{
				if (Input.GetKeyDown((KeyCode)116) && _form == ErenForm.Human)
				{
					BeginShiftToTitan("debug key");
				}
				else if (Input.GetKeyDown((KeyCode)121) && _form == ErenForm.Titan)
				{
					BeginUnshift("debug key");
				}
			}
			switch (_form)
			{
			case ErenForm.Human:
				UpdateFingerBite();
				break;
			case ErenForm.Titan:
				UpdateNapeUnshift();
				_biteHold = 0f;
				_biteLatched = false;
				break;
			default:
				ResetGestureState();
				break;
			}
		}
	}

	private void SetupPreferences()
	{
		_prefs = MelonPreferences.CreateCategory("ErenTitanShifter");
		_injuryShiftEnabled = _prefs.CreateEntry<bool>("InjuryShiftEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_requireEmptyHand = _prefs.CreateEntry<bool>("RequireEmptyHand", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_mouthRadius = _prefs.CreateEntry<float>("MouthRadiusMeters", 0.2f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_biteHoldSeconds = _prefs.CreateEntry<float>("BiteHoldSeconds", 0.28f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeHoldSeconds = _prefs.CreateEntry<float>("NapeTrackedHoldSeconds", 0.3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeBoxMinSide = _prefs.CreateEntry<float>("NapeBoxMinSideMeters", 0.07f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeBoxMaxSide = _prefs.CreateEntry<float>("NapeBoxMaxSideMeters", 0.38f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeBoxBackStart = _prefs.CreateEntry<float>("NapeBoxBackStartMeters", 0.1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeBoxBackEnd = _prefs.CreateEntry<float>("NapeBoxBackEndMeters", 0.42f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeBoxDown = _prefs.CreateEntry<float>("NapeBoxDownMeters", 0.28f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeBoxUp = _prefs.CreateEntry<float>("NapeBoxUpMeters", 0.18f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeTrackingGrace = _prefs.CreateEntry<float>("NapeTrackedGraceSeconds", 0.45f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_requireEmptyHandForUnshift = _prefs.CreateEntry<bool>("RequireEmptyHandForUnshift", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_napeDebugLogging = _prefs.CreateEntry<bool>("NapeDebugLogging", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_unshiftBlockWhileHoldingObject = _prefs.CreateEntry<bool>("UnshiftBlockWhileHoldingObject", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_unshiftArmSeconds = _prefs.CreateEntry<float>("UnshiftArmSeconds", 0.14f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_unshiftSafeHoldSeconds = _prefs.CreateEntry<float>("UnshiftSafeHoldSeconds", 0.48f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_pressurePerDamage = _prefs.CreateEntry<float>("ShiftPressurePerDamage", 1.8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_pressureDecayPerSecond = _prefs.CreateEntry<float>("ShiftPressureDecayPerSecond", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_pressureDecayDelay = _prefs.CreateEntry<float>("ShiftPressureDecayDelaySeconds", 6f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_injuryShiftThreshold = _prefs.CreateEntry<float>("InjuryShiftPressureThreshold", 32f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_maxInjuryShiftChance = _prefs.CreateEntry<float>("MaxInjuryShiftChancePerHit", 0.42f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_teaseChanceAtMaxPressure = _prefs.CreateEntry<float>("TeaseChanceAtMaxPressure", 0.65f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_forceShiftChancePerInjury = _prefs.CreateEntry<float>("ForceShiftChancePerInjury", 0.06f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_forceShiftMinDamage = _prefs.CreateEntry<float>("ForceShiftMinDamage", 6f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_injuryCinematicShiftEnabled = _prefs.CreateEntry<bool>("InjuryCinematicShiftEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_injuryCinematicDuration = _prefs.CreateEntry<float>("InjuryCinematicDurationSeconds", 2.4f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_steamHealingEnabled = _prefs.CreateEntry<bool>("SteamHealingEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_steamHealingRate = _prefs.CreateEntry<float>("SteamHealingPerSecond", 8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_steamHealingDelay = _prefs.CreateEntry<float>("SteamHealingDelayAfterDamageSeconds", 1.25f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_steamHealingVfxScale = _prefs.CreateEntry<float>("SteamHealingVfxScale", 0.35f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_steamHealingVfxInterval = _prefs.CreateEntry<float>("SteamHealingVfxIntervalSeconds", 0.65f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_shiftRestoresFullHealth = _prefs.CreateEntry<bool>("ShiftRestoresFullHealth", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanHealthMultiplier = _prefs.CreateEntry<float>("TitanHealthMultiplier", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanClearanceCheckEnabled = _prefs.CreateEntry<bool>("TitanClearanceCheckEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanClearanceSearchRadius = _prefs.CreateEntry<float>("TitanClearanceSearchRadiusMeters", 1.35f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanStabilityDamageMultiplier = _prefs.CreateEntry<float>("TitanStabilityDamageMultiplier", 1.5f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanStabilityGraceSeconds = _prefs.CreateEntry<float>("TitanStabilityGraceSeconds", 1.25f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_localFlashEnabled = _prefs.CreateEntry<bool>("LocalFlashEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_debugKeysEnabled = _prefs.CreateEntry<bool>("DebugKeyboardKeys", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanRigRefreshEnabled = _prefs.CreateEntry<bool>("TitanRigRefreshEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanRigRefreshHardReset = _prefs.CreateEntry<bool>("TitanRigRefreshHardReset", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanRigRefreshDelay = _prefs.CreateEntry<float>("TitanRigRefreshDelaySeconds", 0.2f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanRigRefreshShutdownSeconds = _prefs.CreateEntry<float>("TitanRigRefreshShutdownSeconds", 0.08f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanHandlingAssistEnabled = _prefs.CreateEntry<bool>("TitanHandlingAssistEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanAgilityTarget = _prefs.CreateEntry<float>("TitanAgilityTarget", 1.55f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanArmResponseMultiplier = _prefs.CreateEntry<float>("TitanArmResponseMultiplier", 1.25f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_vfxEnabled = _prefs.CreateEntry<bool>("VfxEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_sfxEnabled = _prefs.CreateEntry<bool>("SfxEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_vfxIntensity = _prefs.CreateEntry<float>("VfxIntensity", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_sfxVolume = _prefs.CreateEntry<float>("SfxVolume", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_customWavFadeOutSeconds = _prefs.CreateEntry<float>("CustomWavFadeOutSeconds", 0.22f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanVfxScale = _prefs.CreateEntry<float>("TitanVfxScale", 5f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_shiftSwapDelay = _prefs.CreateEntry<float>("ShiftSwapDelaySeconds", 0.34f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_unshiftSwapDelay = _prefs.CreateEntry<float>("UnshiftSwapDelaySeconds", 0.48f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_titanArrivalRoar = _prefs.CreateEntry<bool>("TitanArrivalRoar", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxEnabled = _prefs.CreateEntry<bool>("ExternalVfxEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxScaleMultiplier = _prefs.CreateEntry<float>("ExternalVfxScaleMultiplier", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxReplaceProceduralSteam = _prefs.CreateEntry<bool>("ExternalVfxReplaceProceduralSteam", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxFollowPlayer = _prefs.CreateEntry<bool>("ExternalVfxFollowPlayer", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxFollowMaxSeconds = _prefs.CreateEntry<float>("ExternalVfxFollowMaxSeconds", 3.25f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxMaxEmissionSeconds = _prefs.CreateEntry<float>("ExternalVfxMaxEmissionSeconds", 4.5f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxCleanupGraceSeconds = _prefs.CreateEntry<float>("ExternalVfxCleanupGraceSeconds", 0.2f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_externalVfxHardCleanupSeconds = _prefs.CreateEntry<float>("ExternalVfxHardCleanupSeconds", 14f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_fusionBridgeEnabled = _prefs.CreateEntry<bool>("FusionBridgeEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_fusionOnlyWhenConnected = _prefs.CreateEntry<bool>("FusionOnlyWhenConnected", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_fusionShiftFxSpawnableBarcode = _prefs.CreateEntry<string>("FusionShiftFxSpawnableBarcode", "DeanZSD.ErenTitanShifting.Spawnable.ErenShiftFX", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_fusionUnshiftFxSpawnableBarcode = _prefs.CreateEntry<string>("FusionUnshiftFxSpawnableBarcode", "DeanZSD.ErenTitanShifting.Spawnable.ErenUnshiftFX", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_fusionShiftFxLifetimeSeconds = _prefs.CreateEntry<float>("FusionShiftFxLifetimeSeconds", 8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_fusionUnshiftFxLifetimeSeconds = _prefs.CreateEntry<float>("FusionUnshiftFxLifetimeSeconds", 6f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		_prefs.SaveToFile(false);
	}

	private void SetupBoneMenu()
	{
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_0527: Unknown result type (might be due to invalid IL or missing references)
		//IL_0642: Unknown result typ