Decompiled source of Phainon v1.0.4

PhainonMod.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using AncientScepter;
using BaseVoiceoverLib;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.Commando;
using EntityStates.CursedBook.RitualCircle;
using EntityStates.CursedBook.Spells;
using EntityStates.DroneScrapper;
using EntityStates.Merc.Weapon;
using EntityStates.Missions.ChampRush;
using EntityStates.Reaper;
using HG;
using HG.BlendableTypes;
using HG.Reflection;
using IL.EntityStates.ChampRushReaper;
using IL.RoR2;
using IL.RoR2.CharacterAI;
using IL.RoR2.Items;
using KinematicCharacterController;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using On.EntityStates;
using On.EntityStates.CursedBook.RitualCircle;
using On.EntityStates.Missions.ChampRush;
using On.EntityStates.Reaper;
using On.RoR2;
using On.RoR2.CharacterAI;
using On.RoR2.Items;
using On.RoR2.UI;
using PhainonMod.Components;
using PhainonMod.Content;
using PhainonMod.Core;
using PhainonMod.Hooks;
using PhainonMod.Modules;
using PhainonMod.Net;
using PhainonMod.SkillDefs;
using PhainonMod.SkillStates.Base;
using PhainonMod.SkillStates.Khaslana;
using PhainonMod.SkillStates.Phainon;
using PhainonMod.Survivors;
using PhainonMod.Visuals;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.Audio;
using RoR2.CameraModes;
using RoR2.CharacterAI;
using RoR2.ContentManagement;
using RoR2.EntityLogic;
using RoR2.HudOverlay;
using RoR2.Items;
using RoR2.Navigation;
using RoR2.Networking;
using RoR2.Projectile;
using RoR2.Skills;
using RoR2.Stats;
using RoR2.UI;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Animations;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: IgnoresAccessChecksTo("RoR2")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Joaqi")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4+c908ced2b682b0a7e57ceed4ac9adb88b1bb5ca2")]
[assembly: AssemblyProduct("PhainonMod")]
[assembly: AssemblyTitle("PhainonMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.0")]
[module: UnverifiableCode]
namespace PhainonMod
{
	internal static class Log
	{
		private static ManualLogSource _log;

		internal static void Init(ManualLogSource log)
		{
			_log = log;
		}

		internal static void Debug(object data)
		{
			_log.LogDebug(data);
		}

		internal static void Info(object data)
		{
			_log.LogInfo(data);
		}

		internal static void Trace(object data)
		{
			_log.LogDebug(data);
		}

		internal static void Message(object data)
		{
			_log.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			_log.LogWarning(data);
		}

		internal static void Error(object data)
		{
			_log.LogError(data);
		}

		internal static void Fatal(object data)
		{
			_log.LogFatal(data);
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.Joaqi.PhainonMod", "PhainonMod", "1.0.4")]
	public sealed class PhainonPlugin : BaseUnityPlugin
	{
		public static PhainonPlugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log.Init(((BaseUnityPlugin)this).Logger);
			try
			{
				Config.ReadConfig(((BaseUnityPlugin)this).Config);
				if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
				{
					try
					{
						RiskOfOptionsCompat.Init();
					}
					catch (Exception ex)
					{
						Log.Warning("RiskOfOptions entries skipped: " + ex.Message);
					}
				}
				Asset.Initialize(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location));
				if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
				{
					try
					{
						RiskOfOptionsCompat.SetIcon();
					}
					catch (Exception ex2)
					{
						Log.Warning("RiskOfOptions icon skipped: " + ex2.Message);
					}
				}
				PhainonSounds.Init();
				bool num = Chainloader.PluginInfos.ContainsKey("com.Moffein.BaseVoiceoverLib");
				PhainonVoice.Init(num);
				if (num)
				{
					try
					{
						VoiceoverCompat.Init();
					}
					catch (Exception ex3)
					{
						Log.Warning("Voice lines skipped: " + ex3.Message);
					}
				}
				PhainonEffects.Create();
				PhainonItems.Create();
				PhainonHudGauge.Init();
				KhaslanaHealthCard.Init();
				ConversionTable.Init();
				PhainonBuffs.Create();
				States.RegisterStates();
				Tokens.AddTokens();
				AncientScepterCompat.Init();
				PhainonSurvivor.Create();
				if (AncientScepterCompat.Installed)
				{
					try
					{
						AncientScepterCompat.Register();
					}
					catch (Exception ex4)
					{
						Log.Warning("AncientScepter: Beginning of the End not registered: " + ex4.Message);
					}
				}
				if (Chainloader.PluginInfos.ContainsKey("Def.BazaarIsMyHaven"))
				{
					try
					{
						BazaarCompat.Init();
					}
					catch (Exception ex5)
					{
						Log.Warning("BazaarIsMyHaven: Donation Altar reward skipped: " + ex5.Message);
					}
				}
				PhainonEntrance.Create();
				PhainonDeath.Wire();
				PhainonUmbra.CreateMaster();
				PhainonHooks.Init();
				FormStateNet.Register();
				ScourgeNet.Register();
				new ContentPacks().Initialize();
			}
			catch (Exception arg)
			{
				Log.Error(string.Format("{0} failed to load: {1}", "PhainonMod", arg));
				return;
			}
			Log.Info(string.Format("{0} {1} loaded: {2} entity states, ", "PhainonMod", "1.0.4", States.entityStates.Count) + $"{Skills.skillDefs.Count} skill defs, {PhainonItems.All.Count} items, {PhainonBuffs.All.Count} buffs, " + $"{Prefabs.bodyPrefabs.Count} bodies, {Prefabs.masterPrefabs.Count} masters.");
		}
	}
	internal static class PluginInfo
	{
		public const string Guid = "com.Joaqi.PhainonMod";

		public const string Name = "PhainonMod";

		public const string Version = "1.0.4";

		public const string Author = "Joaqi";
	}
}
namespace PhainonMod.Visuals
{
	internal sealed class BladeRibbon : MonoBehaviour
	{
		private struct Sample
		{
			internal Vector3 grip;

			internal Vector3 direction;

			internal float length;

			internal float time;

			internal float strength;
		}

		internal const string GripEntry = "SwordBase";

		internal const string TipEntry = "SwordTip";

		internal static float Lifetime = 0.1f;

		internal static float Lead = 0.15f;

		internal static float Trail = 0.15f;

		internal static float InnerFraction = 0.3f;

		internal static float InnerAlpha = 0.35f;

		internal static float SpeedLow = 6f;

		internal static float SpeedHigh = 20f;

		internal static float FadePower = 1.5f;

		internal static bool FlipU = false;

		internal static float UStart = 0.5f;

		internal static float VMargin = 0f;

		private const float StepDegrees = 4f;

		private const int MaxSteps = 16;

		private readonly List<Sample> samples = new List<Sample>();

		private readonly List<Vector3> vertices = new List<Vector3>();

		private readonly List<Color> colors = new List<Color>();

		private readonly List<Vector2> uvs = new List<Vector2>();

		private readonly List<int> triangles = new List<int>();

		private Transform grip;

		private Transform tip;

		private Mesh mesh;

		private bool doubleSided;

		private bool emitting = true;

		private bool frozen;

		private float clock;

		internal static int Live { get; private set; }

		internal static BladeRibbon Spawn(Transform model, Transform gripEntry, Transform tipEntry, Material material)
		{
			//IL_0035: 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_004b: 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_0080: 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)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			Transform val = ShownSource(gripEntry);
			Transform val2 = ShownSource(tipEntry);
			if (!Object.op_Implicit((Object)(object)model) || !Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)material))
			{
				return null;
			}
			GameObject val3 = new GameObject("PhainonBladeRibbon")
			{
				layer = ((Component)model).gameObject.layer
			};
			val3.transform.SetParent(model, false);
			MeshRenderer obj = val3.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterial = material;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			((Renderer)obj).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)obj).reflectionProbeUsage = (ReflectionProbeUsage)0;
			BladeRibbon bladeRibbon = val3.AddComponent<BladeRibbon>();
			bladeRibbon.grip = val;
			bladeRibbon.tip = val2;
			bladeRibbon.doubleSided = !material.HasProperty("_Cull");
			bladeRibbon.mesh = new Mesh
			{
				name = "PhainonBladeRibbon"
			};
			bladeRibbon.mesh.MarkDynamic();
			val3.AddComponent<MeshFilter>().sharedMesh = bladeRibbon.mesh;
			return bladeRibbon;
		}

		internal static void ShownBlade(ChildLocator locator, out Transform grip, out Transform tip)
		{
			grip = ShownSource(Object.op_Implicit((Object)(object)locator) ? locator.FindChild("SwordBase") : null);
			tip = ShownSource(Object.op_Implicit((Object)(object)locator) ? locator.FindChild("SwordTip") : null);
		}

		private static Transform ShownSource(Transform entry)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			ParentConstraint val = (Object.op_Implicit((Object)(object)entry) ? ((Component)entry).GetComponent<ParentConstraint>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return entry;
			}
			Transform val2 = null;
			float num = 0f;
			for (int i = 0; i < val.sourceCount; i++)
			{
				ConstraintSource source = val.GetSource(i);
				if (Object.op_Implicit((Object)(object)((ConstraintSource)(ref source)).sourceTransform) && ((Component)((ConstraintSource)(ref source)).sourceTransform).gameObject.activeInHierarchy && ((ConstraintSource)(ref source)).weight > num)
				{
					val2 = ((ConstraintSource)(ref source)).sourceTransform;
					num = ((ConstraintSource)(ref source)).weight;
				}
			}
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return entry;
			}
			return val2;
		}

		internal void Stop()
		{
			emitting = false;
		}

		internal void SetFrozen(bool value)
		{
			frozen = value;
		}

		private void OnEnable()
		{
			Live++;
		}

		private void OnDisable()
		{
			Live--;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)mesh))
			{
				Object.Destroy((Object)(object)mesh);
			}
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)grip) || !Object.op_Implicit((Object)(object)tip))
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			if (!frozen)
			{
				clock += Time.deltaTime;
				if (emitting)
				{
					AddSample();
				}
			}
			while (samples.Count > 1 && clock - samples[1].time > Lifetime)
			{
				samples.RemoveAt(0);
			}
			if (!emitting && (samples.Count == 0 || clock - samples[samples.Count - 1].time > Lifetime))
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
			else
			{
				Rebuild();
			}
		}

		private void AddSample()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_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_0035: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_0085: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)this).transform.InverseTransformPoint(grip.position);
			Vector3 val2 = ((Component)this).transform.InverseTransformPoint(tip.position);
			Vector3 val3 = val2 - val;
			float magnitude = ((Vector3)(ref val3)).magnitude;
			if (!(magnitude < 0.0001f))
			{
				float strength = 0f;
				if (samples.Count > 0 && Time.deltaTime > 0f)
				{
					Sample sample = samples[samples.Count - 1];
					Vector3 val4 = val2 - (sample.grip + sample.direction * sample.length);
					float num = ((Vector3)(ref val4)).magnitude / Time.deltaTime;
					strength = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(SpeedLow, SpeedHigh, num));
				}
				samples.Add(new Sample
				{
					grip = val,
					direction = val3 / magnitude,
					length = magnitude,
					time = clock,
					strength = strength
				});
			}
		}

		private void Rebuild()
		{
			//IL_0077: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: 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_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: 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_00e4: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			vertices.Clear();
			colors.Clear();
			uvs.Clear();
			triangles.Clear();
			int count = samples.Count;
			if (count >= 2)
			{
				for (int i = 0; i < count - 1; i++)
				{
					Sample sample = samples[i];
					Sample sample2 = samples[i + 1];
					Vector3 p = samples[Mathf.Max(i - 1, 0)].grip;
					Vector3 p2 = samples[Mathf.Min(i + 2, count - 1)].grip;
					int num = Mathf.Clamp(Mathf.CeilToInt(Vector3.Angle(sample.direction, sample2.direction) / 4f), 1, 16);
					for (int j = 0; j < num; j++)
					{
						float num2 = (float)j / (float)num;
						AddPoint(CatmullRom(p, sample.grip, sample2.grip, p2, num2), Vector3.Slerp(sample.direction, sample2.direction, num2), Mathf.Lerp(sample.length, sample2.length, num2), Mathf.Lerp(sample.time, sample2.time, num2), Mathf.Lerp(sample.strength, sample2.strength, num2));
					}
				}
				Sample sample3 = samples[count - 1];
				AddPoint(sample3.grip, sample3.direction, sample3.length, sample3.time, sample3.strength);
				for (int k = 0; k + 3 < vertices.Count; k += 2)
				{
					triangles.Add(k);
					triangles.Add(k + 1);
					triangles.Add(k + 2);
					triangles.Add(k + 1);
					triangles.Add(k + 3);
					triangles.Add(k + 2);
					if (doubleSided)
					{
						triangles.Add(k);
						triangles.Add(k + 2);
						triangles.Add(k + 1);
						triangles.Add(k + 1);
						triangles.Add(k + 2);
						triangles.Add(k + 3);
					}
				}
			}
			mesh.Clear();
			mesh.SetVertices(vertices);
			mesh.SetColors(colors);
			mesh.SetUVs(0, uvs);
			mesh.SetTriangles(triangles, 0);
			mesh.RecalculateBounds();
		}

		private void AddPoint(Vector3 gripPoint, Vector3 direction, float length, float time, float strength)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00d5: 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)
			float num = Mathf.Clamp01((clock - time) / Lifetime);
			float num2 = strength * Mathf.Pow(1f - num, FadePower);
			float num3 = Mathf.Lerp(UStart, 1f, num);
			num3 = (FlipU ? (1f - num3) : num3);
			vertices.Add(gripPoint + direction * (length * InnerFraction));
			colors.Add(new Color(1f, 1f, 1f, num2 * InnerAlpha));
			uvs.Add(new Vector2(num3, VMargin));
			vertices.Add(gripPoint + direction * length);
			colors.Add(new Color(1f, 1f, 1f, num2));
			uvs.Add(new Vector2(num3, 1f - VMargin));
		}

		private static Vector3 CatmullRom(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			float num = t * t;
			float num2 = num * t;
			return 0.5f * (2f * p1 + (p2 - p0) * t + (2f * p0 - 5f * p1 + 4f * p2 - p3) * num + (3f * p1 - p0 - 3f * p2 + p3) * num2);
		}
	}
	internal sealed class FxSprite
	{
		internal string name;

		internal Material material;

		internal float aspect = 1f;
	}
	internal static class BloodthornFx
	{
		private struct Tint
		{
			internal Material material;

			internal int property;

			internal Color recoloured;

			internal bool fades;
		}

		internal const string ChargeName = "PhainonBloodthornCharge";

		internal const int AdditiveQueue = 3010;

		internal static float CoreScale = 1f;

		internal static float CoreBrightness = 0.3f;

		internal static float CoreOpacity = 0.4f;

		internal static readonly Dictionary<string, bool> CoreParts = DefaultCoreParts();

		internal static float ChargeScale = 1f;

		internal static float ChargeIntensity = 1f;

		internal static float DevTimeScale = 1f;

		internal static float AdditiveBoost = 1f;

		internal static float AdditiveAlphaBoost = 0.5f;

		internal static float RampHotStart = 0.86f;

		internal static Color RampDeep = new Color(0.42f, 0.3f, 0.04f);

		internal static Color RampGold = new Color(1f, 0.82f, 0.32f);

		internal static Color RampHot = new Color(1f, 0.94f, 0.72f);

		internal static float ChargeLife = 0.3f;

		internal static int ArcCount = 4;

		internal static float ArcLength = 0.9f;

		internal static float ArcWidth = 0.2f;

		internal static int ArcSegments = 10;

		internal static float ArcJitter = 0.12f;

		internal static float ArcReroll = 0.035f;

		internal static float ArcCrawl = 0.6f;

		internal static float ArcTilt = 18f;

		internal static Color ArcTint = new Color(1f, 1f, 1f, 1f);

		internal static float ChargeCoreFrom = 0.3f;

		internal static float ChargeCoreTo = 1.3f;

		internal static Color ChargeCoreTint = new Color(1f, 0.97f, 0.85f, 1f);

		internal static Color ChargeLightColor = new Color(1f, 0.82f, 0.32f);

		internal static float ChargeLightIntensity = 3f;

		internal static float ChargeLightRange = 0.8f;

		internal static float BlastSwordPoint = 0.5f;

		internal static bool CasterFlashOn = true;

		internal static Color CasterFlashColor = new Color(1f, 0.92f, 0.65f);

		internal static float CasterFlashPeak = 0.2f;

		internal static float CasterFlashRampIn = 0.02f;

		internal static float CasterFlashHold = 0.03f;

		internal static float CasterFlashFade = 0.14f;

		internal static float CasterFlashHdr = 1f;

		internal static GameObject charge;

		internal static string summary = "not built";

		internal static FxSprite core;

		internal static Material arcMaterial;

		private static readonly List<Material> windUpMaterials = new List<Material>();

		private static string basisGains = "?";

		private static readonly List<Tint> coreTints = new List<Tint>();

		private static string coreNote = "not converted";

		private static string coreDetail = "not converted";

		private static string partsNote = "not set";

		private static GameObject holder;

		private static Mesh centredQuad;

		private static readonly List<string> failed = new List<string>();

		private static readonly string[] CoreSeeThroughMaterials = new string[1] { "matVoidCrabAntiMatterParticleDonut" };

		private const string CoreShaderSource = "matVoidCrabAntiMatterParticleSphere";

		private const string CoreRampName = "texRampMatterAntimatter";

		private const string CoreRampAlpha = "alpha 0 below index ~0.36, 1 above (bundle dump)";

		private static readonly Dictionary<string, string> CloudRemapToggles = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			{ "_DisableRemapOn", "DISABLEREMAP" },
			{ "_UseUV1On", "USE_UV1" },
			{ "_FadeCloseOn", "FADECLOSE" },
			{ "_CloudsOn", "USE_CLOUDS" },
			{ "_CloudOffsetOn", "CLOUDOFFSET" },
			{ "_VertexColorOn", "VERTEXCOLOR" },
			{ "_VertexAlphaOn", "VERTEXALPHA" },
			{ "_CalcTextureAlphaOn", "CALCTEXTUREALPHA" },
			{ "_VertexOffsetOn", "VERTEXOFFSET" },
			{ "_FresnelOn", "FRESNEL" },
			{ "_SkyboxOnly", "SKYBOX_ONLY" }
		};

		private static Texture2D goldRamp;

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

		internal const float StrokeBody = 0.3f;

		internal const float StrokeCore = 0.12f;

		internal static Mesh CentredQuad
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)centredQuad))
				{
					return centredQuad = BuildQuad("PhainonFxQuadCentred");
				}
				return centredQuad;
			}
		}

		internal static Texture2D GoldRamp
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: 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)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Expected O, but got Unknown
				if (!Object.op_Implicit((Object)(object)goldRamp))
				{
					goldRamp = new Texture2D(256, 1, (TextureFormat)4, false)
					{
						name = "texPhainonRampBloodthornGold",
						wrapMode = (TextureWrapMode)1,
						filterMode = (FilterMode)1,
						hideFlags = (HideFlags)61
					};
					FillGoldRamp();
				}
				return goldRamp;
			}
		}

		private static Dictionary<string, bool> DefaultCoreParts()
		{
			Dictionary<string, bool> dictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
			string[] bloodthornCoreOff = PhainonEffects.BloodthornCoreOff;
			foreach (string key in bloodthornCoreOff)
			{
				dictionary[key] = false;
			}
			return dictionary;
		}

		internal static void ResetCoreParts()
		{
			CoreParts.Clear();
			foreach (KeyValuePair<string, bool> item in DefaultCoreParts())
			{
				CoreParts[item.Key] = item.Value;
			}
		}

		internal static bool CorePartDrawn(string childName)
		{
			bool result = true;
			int num = -1;
			foreach (KeyValuePair<string, bool> corePart in CoreParts)
			{
				if (corePart.Key.Length > num && (childName ?? "").StartsWith(corePart.Key, StringComparison.OrdinalIgnoreCase))
				{
					num = corePart.Key.Length;
					result = corePart.Value;
				}
			}
			return result;
		}

		internal static void ApplyCoreParts(ParticleSystemRenderer[] renderers, Transform root)
		{
			foreach (ParticleSystemRenderer val in renderers)
			{
				if (Object.op_Implicit((Object)(object)val) && (Object)(object)((Component)val).transform != (Object)(object)root)
				{
					((Renderer)val).enabled = CorePartDrawn(((Object)((Component)val).gameObject).name);
				}
			}
		}

		internal static string CorePartRules()
		{
			if (CoreParts.Count != 0)
			{
				return string.Join(", ", CoreParts.Select((KeyValuePair<string, bool> p) => "'" + p.Key + "' " + (p.Value ? "on" : "off")));
			}
			return "none";
		}

		internal static string CorePartsNote(GameObject clone)
		{
			if (!Object.op_Implicit((Object)(object)clone))
			{
				return "no core clone";
			}
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			ParticleSystemRenderer[] componentsInChildren = clone.GetComponentsInChildren<ParticleSystemRenderer>(true);
			foreach (ParticleSystemRenderer val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val) && !((Object)(object)((Component)val).transform == (Object)(object)clone.transform))
				{
					string name = ((Object)((Component)val).gameObject).name;
					if (!((Component)val).gameObject.activeSelf)
					{
						list2.Add("'" + name + "'");
					}
					else
					{
						list.Add("'" + name + "' " + (CorePartDrawn(name) ? "on" : "off"));
					}
				}
			}
			return "parts " + string.Join(", ", list) + " (rules " + CorePartRules() + ", per spawn)" + ((list2.Count > 0) ? ("; inactive in the prefab: " + string.Join(", ", list2)) : "");
		}

		private static Mesh BuildQuad(string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_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_007e: 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_00a0: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_015a: 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)
			Mesh val = new Mesh();
			((Object)val).name = name;
			((Object)val).hideFlags = (HideFlags)61;
			val.vertices = (Vector3[])(object)new Vector3[4]
			{
				new Vector3(-0.5f, -0.5f, 0f),
				new Vector3(0.5f, -0.5f, 0f),
				new Vector3(0.5f, 0.5f, 0f),
				new Vector3(-0.5f, 0.5f, 0f)
			};
			val.uv = (Vector2[])(object)new Vector2[4]
			{
				new Vector2(0f, 0f),
				new Vector2(1f, 0f),
				new Vector2(1f, 1f),
				new Vector2(0f, 1f)
			};
			val.colors = (Color[])(object)new Color[4]
			{
				Color.white,
				Color.white,
				Color.white,
				Color.white
			};
			val.normals = (Vector3[])(object)new Vector3[4]
			{
				Vector3.back,
				Vector3.back,
				Vector3.back,
				Vector3.back
			};
			val.triangles = new int[6] { 0, 3, 2, 0, 2, 1 };
			return val;
		}

		internal static void Build()
		{
			failed.Clear();
			core = Layer("charge core", () => AdditiveFrom("texPhainonFxCore", CinematicFx.FlareTexture));
			arcMaterial = Layer("charge arcs", () => AdditiveFrom("texPhainonFxLine", LineTexture(64, 16)))?.material;
			charge = Guard("charge EffectDef", () => BuildTemplate("PhainonBloodthornCharge", ChargeLife, typeof(BloodthornChargeFx)));
			Guard("core parts", delegate
			{
				partsNote = InstallCoreParts();
				return "";
			});
			Guard("core see-through", delegate
			{
				SeeThroughCore();
				return "";
			});
			Guard("blast tints", delegate
			{
				CollectTints(coreTints, "bloodthornCore");
				return "";
			});
			Guard("tuning", delegate
			{
				ApplyTuning();
				return "";
			});
			if (Object.op_Implicit((Object)(object)PhainonEffects.bloodthornCore))
			{
				Log.Info($"Effects: {((Object)PhainonEffects.bloodthornCore).name} see-through (CoreOpacity {CoreOpacity:0.##}): {coreDetail}; " + "alpha x CoreOpacity on " + FadingNames(coreTints));
			}
			summary = "blast at the blade [core " + BlastLayer(PhainonEffects.bloodthornCore, "bloodthornCore", CoreScale) + "; " + partsNote + "]; " + string.Format("charge {0} [{1} arcs {2}, core {3}; gold ramp ", Describe(charge), ArcCount, Object.op_Implicit((Object)(object)arcMaterial) ? "on" : "off", On(core)) + $"(hot from {RampHotStart:0.##}), _Boost {AdditiveBoost:0.##}, _AlphaBoost {AdditiveAlphaBoost:0.##} (basis {basisGains})]" + ((failed.Count > 0) ? ("; failed: " + string.Join(", ", failed)) : "");
			Log.Info("Effects: Bloodthorn Ferry built (" + summary + ")");
		}

		private static T Guard<T>(string what, Func<T> build) where T : class
		{
			try
			{
				return build();
			}
			catch (Exception ex)
			{
				failed.Add(what);
				Log.Warning("Effects: Bloodthorn Ferry: " + what + " threw " + ex.GetType().Name + ": " + ex.Message + "; skipped, the rest still builds");
				return null;
			}
		}

		private static FxSprite Layer(string what, Func<FxSprite> build)
		{
			FxSprite fxSprite = Guard(what, build);
			if (fxSprite == null || !Object.op_Implicit((Object)(object)fxSprite.material))
			{
				return null;
			}
			return fxSprite;
		}

		private static string On(FxSprite sprite)
		{
			if (sprite == null || !Object.op_Implicit((Object)(object)sprite.material))
			{
				return "off";
			}
			return "on";
		}

		private static string Describe(GameObject prefab)
		{
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return "none";
			}
			return "EffectDef " + ((Object)prefab).name;
		}

		private static string BlastLayer(GameObject clone, string field, float factor)
		{
			if (!Object.op_Implicit((Object)(object)clone))
			{
				return "off (no clone)";
			}
			TintReport tintReport = PhainonEffects.Find(field)?.tint;
			int num = (from t in coreTints
				where t.fades
				select t.material).Distinct().Count();
			return ((Object)clone).name + " (" + ((tintReport != null) ? (tintReport.blendedRampsKept + " own ramps kept, ") : "") + "see-through: " + coreNote + "; " + $"opacity {CoreOpacity:0.##} on {num} alpha-blended material(s); scale = radius x {factor:0.##})";
		}

		private static void CollectTints(List<Tint> into, string field)
		{
			into.Clear();
			PhainonEffects.Entry entry = PhainonEffects.Find(field);
			if (entry != null && Object.op_Implicit((Object)(object)entry.prefab) && entry.tint != null)
			{
				AddTints(into, entry.tint);
			}
		}

		private static void AddTints(List<Tint> into, TintReport report)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			foreach (Material item in report.created)
			{
				if (!Object.op_Implicit((Object)(object)item))
				{
					continue;
				}
				bool fades = AlphaBlended(item);
				string[] tintProperties = PhainonEffects.TintProperties;
				foreach (string text in tintProperties)
				{
					if (item.HasProperty(text))
					{
						into.Add(new Tint
						{
							material = item,
							property = Shader.PropertyToID(text),
							recoloured = item.GetColor(text),
							fades = fades
						});
					}
				}
			}
		}

		private static void ApplyTints(List<Tint> tints, float brightness, float opacity)
		{
			//IL_0032: 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_0045: 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_0057: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(0f, brightness);
			float num2 = Mathf.Clamp01(opacity);
			foreach (Tint tint in tints)
			{
				if (Object.op_Implicit((Object)(object)tint.material))
				{
					Color recoloured = tint.recoloured;
					tint.material.SetColor(tint.property, new Color(recoloured.r * num, recoloured.g * num, recoloured.b * num, tint.fades ? (recoloured.a * num2) : recoloured.a));
				}
			}
		}

		private static bool AlphaBlended(Material m)
		{
			if (!BlendPair(m, "_SrcBlend", "_DstBlend"))
			{
				return BlendPair(m, "_SrcBlendFloat", "_DstBlendFloat");
			}
			return true;
		}

		private static bool BlendPair(Material m, string src, string dst)
		{
			if (m.HasProperty(src) && m.HasProperty(dst) && Mathf.RoundToInt(m.GetFloat(src)) == 5)
			{
				return Mathf.RoundToInt(m.GetFloat(dst)) == 10;
			}
			return false;
		}

		private static string FadingNames(List<Tint> tints)
		{
			List<string> list = (from t in tints
				where t.fades && Object.op_Implicit((Object)(object)t.material)
				select ((Object)t.material).name).Distinct().ToList();
			if (list.Count != 0)
			{
				return string.Format("{0} material(s): {1}", list.Count, string.Join(", ", list));
			}
			return "none";
		}

		private static string InstallCoreParts()
		{
			GameObject bloodthornCore = PhainonEffects.bloodthornCore;
			if (!Object.op_Implicit((Object)(object)bloodthornCore))
			{
				return "no core clone";
			}
			if (!Object.op_Implicit((Object)(object)bloodthornCore.GetComponent<BloodthornCoreParts>()))
			{
				bloodthornCore.AddComponent<BloodthornCoreParts>();
			}
			ApplyCoreParts(bloodthornCore.GetComponentsInChildren<ParticleSystemRenderer>(true), bloodthornCore.transform);
			return CorePartsNote(bloodthornCore);
		}

		internal static void SeeThroughCore()
		{
			coreNote = "not converted";
			coreDetail = "not converted";
			PhainonEffects.Entry entry = PhainonEffects.Find("bloodthornCore");
			if (entry == null || !Object.op_Implicit((Object)(object)entry.prefab) || entry.tint == null)
			{
				coreNote = (coreDetail = "no core clone");
				return;
			}
			List<Material> list = entry.tint.created.Where((Material val3) => Object.op_Implicit((Object)(object)val3)).ToList();
			Material val = ((IEnumerable<Material>)list).FirstOrDefault((Func<Material, bool>)((Material val3) => IsCloudRemap(val3) && ((Object)val3).name.StartsWith("matVoidCrabAntiMatterParticleSphere", StringComparison.Ordinal))) ?? ((IEnumerable<Material>)list).FirstOrDefault((Func<Material, bool>)IsCloudRemap);
			Shader val2;
			string shaderFrom;
			if ((Object)(object)val != (Object)null)
			{
				val2 = val.shader;
				shaderFrom = ((Object)val).name;
			}
			else
			{
				val2 = PhainonEffects.PlainCloudRemapShader(out var from);
				shaderFrom = "the plain shell basis " + from;
			}
			if (!Object.op_Implicit((Object)(object)val2))
			{
				coreNote = (coreDetail = "no Cloud Remap shader, the donut stays opaque");
				WarnOnce("no Hopoo Games/FX/Cloud Remap shader on the core or the plain shell basis; the core's donut ring stays opaque (the blast still spawns; CoreOpacity still thins its other alpha-blended materials)");
				return;
			}
			List<string> list2 = new List<string>();
			List<string> list3 = new List<string>();
			foreach (Material m in list)
			{
				if (CoreSeeThroughMaterials.Any((string prefix) => ((Object)m).name.StartsWith(prefix, StringComparison.Ordinal)))
				{
					if ((Object)(object)m.shader == (Object)(object)val2)
					{
						list3.Add(((Object)m).name + ": already " + ((Object)val2).name);
						continue;
					}
					list3.Add(ToAlphaBlended(m, val2, shaderFrom, out var brief));
					list2.Add(brief);
				}
			}
			if (list3.Count == 0)
			{
				coreNote = (coreDetail = "no donut material on the core, nothing converted");
				WarnOnce("the core has no " + string.Join("/", CoreSeeThroughMaterials) + " instance; nothing converted (the blast still spawns)");
			}
			else
			{
				coreNote = ((list2.Count > 0) ? string.Join(", ", list2) : "donut already alpha-blended");
				coreDetail = string.Join("; ", list3);
			}
		}

		private static bool IsCloudRemap(Material m)
		{
			if (Object.op_Implicit((Object)(object)m) && Object.op_Implicit((Object)(object)m.shader))
			{
				return ((Object)m.shader).name == "Hopoo Games/FX/Cloud Remap";
			}
			return false;
		}

		private static string ToAlphaBlended(Material m, Shader shader, string shaderFrom, out string brief)
		{
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			string text = (Object.op_Implicit((Object)(object)m.shader) ? ((Object)m.shader).name : "no shader");
			int renderQueue = m.renderQueue;
			string text2 = string.Join(" ", m.shaderKeywords.OrderBy<string, string>((string k) => k, StringComparer.Ordinal));
			m.shader = shader;
			string text3 = Float(m, "_AlphaBias");
			SetIfPresent(m, "_AlphaBias", 0f);
			SetIfPresent(m, "_SrcBlend", 5f);
			SetIfPresent(m, "_DstBlend", 10f);
			bool flag = m.HasProperty("_ZWrite");
			SetIfPresent(m, "_ZWrite", 0f);
			m.renderQueue = 3000;
			foreach (KeyValuePair<string, string> cloudRemapToggle in CloudRemapToggles)
			{
				if (m.HasProperty(cloudRemapToggle.Key))
				{
					if (m.GetFloat(cloudRemapToggle.Key) != 0f)
					{
						m.EnableKeyword(cloudRemapToggle.Value);
					}
					else
					{
						m.DisableKeyword(cloudRemapToggle.Value);
					}
				}
			}
			m.DisableKeyword("CLOUDNORMAL");
			string text4 = string.Join(" ", m.shaderKeywords.OrderBy<string, string>((string k) => k, StringComparer.Ordinal));
			Texture val = (m.HasProperty("_RemapTex") ? m.GetTexture("_RemapTex") : null);
			object obj2;
			if (Object.op_Implicit((Object)(object)val))
			{
				string[] obj = new string[6]
				{
					((Object)val).name,
					" (",
					null,
					null,
					null,
					null
				};
				Texture2D val2 = (Texture2D)(object)((val is Texture2D) ? val : null);
				obj[2] = ((val2 != null) ? $"{val2.format}, readable {((Texture)val2).isReadable}" : ((object)val).GetType().Name);
				obj[3] = "; ";
				obj[4] = ((((Object)val).name == "texRampMatterAntimatter") ? "alpha 0 below index ~0.36, 1 above (bundle dump)" : "alpha not known for this ramp");
				obj[5] = ")";
				obj2 = string.Concat(obj);
			}
			else
			{
				obj2 = "no ramp";
			}
			string text5 = (string)obj2;
			brief = "donut " + Short(text) + " -> " + Short(((Object)m.shader).name) + " " + Float(m, "_SrcBlend") + "/" + Float(m, "_DstBlend") + ", " + string.Format("queue {0} -> {1}, ramp {2} ", renderQueue, m.renderQueue, Object.op_Implicit((Object)(object)val) ? ((Object)val).name : "none") + ((Object.op_Implicit((Object)(object)val) && ((Object)val).name == "texRampMatterAntimatter") ? "alpha 0 below ~0.36, 1 above" : "alpha unknown");
			return ((Object)m).name + ": " + text + " -> " + ((Object)m.shader).name + " (from " + shaderFrom + "), _SrcBlend " + Float(m, "_SrcBlend") + ", _DstBlend " + Float(m, "_DstBlend") + ", zWrite " + (flag ? ("_ZWrite " + Float(m, "_ZWrite")) : "0 (fixed by the shader)") + ", " + $"queue {renderQueue} -> {m.renderQueue}, keywords [{text2}] -> [{text4}], _AlphaBias {text3} -> " + Float(m, "_AlphaBias") + ", _AlphaBoost " + Float(m, "_AlphaBoost") + ", _InvFade " + Float(m, "_InvFade") + ", _Cull " + Float(m, "_Cull") + ", ramp " + text5;
		}

		private static string Short(string shaderName)
		{
			int num = shaderName.LastIndexOf('/');
			if (num < 0)
			{
				return shaderName;
			}
			return shaderName.Substring(num + 1);
		}

		private static FxSprite AdditiveFrom(string name, Texture2D texture)
		{
			if (!Object.op_Implicit((Object)(object)texture))
			{
				return null;
			}
			Material val = PhainonEffects.BuildFlareMaterial("mat" + name.Substring(3), (Texture)(object)texture, PhainonEffects.PhainonPalette);
			if (!Object.op_Implicit((Object)(object)val))
			{
				WarnOnce("no plain Cloud Remap material: the wind-up's core and arcs are off");
				return null;
			}
			val.renderQueue = Mathf.Max(val.renderQueue, 3010);
			if (windUpMaterials.Count == 0)
			{
				basisGains = "_Boost " + Float(val, "_Boost") + ", _AlphaBoost " + Float(val, "_AlphaBoost");
			}
			if (val.HasProperty("_RemapTex"))
			{
				val.SetTexture("_RemapTex", (Texture)(object)GoldRamp);
			}
			windUpMaterials.Add(val);
			return new FxSprite
			{
				name = name,
				material = val,
				aspect = Aspect((Texture)(object)texture)
			};
		}

		private static string Float(Material m, string property)
		{
			if (!m.HasProperty(property))
			{
				return "none";
			}
			return m.GetFloat(property).ToString("0.##", CultureInfo.InvariantCulture);
		}

		internal static void ApplyTuning()
		{
			FillGoldRamp();
			foreach (Material windUpMaterial in windUpMaterials)
			{
				SetIfPresent(windUpMaterial, "_Boost", AdditiveBoost);
				SetIfPresent(windUpMaterial, "_AlphaBoost", AdditiveAlphaBoost);
				SetIfPresent(windUpMaterial, "_AlphaBias", 0f);
			}
			ApplyTints(coreTints, CoreBrightness, CoreOpacity);
		}

		private static void SetIfPresent(Material m, string property, float value)
		{
			if (Object.op_Implicit((Object)(object)m) && m.HasProperty(property))
			{
				m.SetFloat(property, value);
			}
		}

		private static void FillGoldRamp()
		{
			//IL_006c: 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_007e: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)goldRamp))
			{
				float num = Mathf.Clamp(RampHotStart, 0.35f, 0.98f);
				float num2 = Mathf.Lerp(num, 1f, 0.55f);
				Color[] array = (Color[])(object)new Color[256];
				for (int i = 0; i < 256; i++)
				{
					float num3 = (float)i / 255f;
					Color val = ((!(num3 < 0.12f)) ? ((!(num3 < 0.3f)) ? ((!(num3 < num)) ? ((!(num3 < num2)) ? Color.Lerp(RampHot, Color.white, (num3 - num2) / (1f - num2)) : Color.Lerp(RampGold, RampHot, (num3 - num) / (num2 - num))) : RampGold) : Color.Lerp(RampDeep, RampGold, (num3 - 0.12f) / 0.18f)) : Color.Lerp(new Color(0f, 0f, 0f, 0f), RampDeep, num3 / 0.12f));
					val.a = ((num3 < 0.12f) ? (num3 / 0.12f) : 1f);
					array[i] = val;
				}
				goldRamp.SetPixels(array);
				goldRamp.Apply(false, false);
			}
		}

		private static float Aspect(Texture texture)
		{
			if (!Object.op_Implicit((Object)(object)texture) || texture.height <= 0)
			{
				return 1f;
			}
			return (float)texture.width / (float)texture.height;
		}

		private static void WarnOnce(string what)
		{
			if (warned.Add(what))
			{
				Log.Warning("Effects: Bloodthorn Ferry: " + what);
			}
		}

		private static Texture2D NewTexture(string name, int width, int height)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			return new Texture2D(width, height, (TextureFormat)4, true, true)
			{
				name = name,
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)2,
				hideFlags = (HideFlags)61
			};
		}

		private static Texture2D Finish(Texture2D texture, float[] values)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Color32[] array = (Color32[])(object)new Color32[values.Length];
			for (int i = 0; i < values.Length; i++)
			{
				byte b = (byte)Mathf.RoundToInt(Mathf.Clamp01(values[i]) * 255f);
				array[i] = new Color32(b, b, b, b);
			}
			texture.SetPixels32(array);
			texture.Apply(true, true);
			return texture;
		}

		private static Texture2D LineTexture(int width, int height)
		{
			float[] array = new float[width * height];
			for (int i = 0; i < height; i++)
			{
				float num = ((float)i + 0.5f) / (float)height;
				float num2 = Profile(Mathf.Abs(2f * num - 1f), 0.3f, 0.12f);
				for (int j = 0; j < width; j++)
				{
					array[i * width + j] = num2;
				}
			}
			return Finish(NewTexture("texPhainonFxLine", width, height), array);
		}

		private static float Profile(float q, float body, float core)
		{
			q = Mathf.Clamp01(q);
			return body * (1f - Mathf.SmoothStep(0.35f, 1f, q)) + (1f - body) * (1f - Mathf.SmoothStep(0f, core, q));
		}

		private static GameObject BuildTemplate(string name, float life, Type driver)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_005b: 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_006f: 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_00a4: Expected O, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)holder))
			{
				holder = new GameObject("PhainonBloodthornFxTemplates");
				holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)holder);
			}
			GameObject val = new GameObject(name);
			val.transform.SetParent(holder.transform, false);
			EffectComponent obj = val.AddComponent<EffectComponent>();
			obj.applyScale = false;
			obj.effectIndex = (EffectIndex)(-1);
			VFXAttributes obj2 = val.AddComponent<VFXAttributes>();
			obj2.vfxPriority = (VFXPriority)2;
			obj2.vfxIntensity = (VFXIntensity)1;
			obj2.DoNotPool = true;
			val.AddComponent<DestroyOnTimer>().duration = life + 0.25f;
			val.AddComponent(driver);
			Asset.effectDefs.Add(new EffectDef(val));
			PhainonEffects.AddEntry(name, name, "built in code", val, effectDef: true, $"Bloodthorn Ferry, {life:0.##} s, never pooled");
			return val;
		}

		internal static void SpawnBlast(Vector3 centre, Quaternion facing, float radius, bool transmit = true)
		{
			//IL_000a: 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)
			SpawnScaled(PhainonEffects.bloodthornCore, "Bloodthorn blast core", centre, facing, radius * CoreScale, transmit);
		}

		internal static void SpawnCharge(Vector3 centre, Quaternion facing, float radius, bool transmit = true)
		{
			//IL_000a: 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)
			SpawnScaled(charge, "Bloodthorn charge", centre, facing, Mathf.Max(0.5f, radius), transmit);
		}

		internal static void SpawnScaled(GameObject prefab, string what, Vector3 centre, Quaternion facing, float scale, bool transmit)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)prefab) && !(scale <= 0f) && EffectCheck.IsRegistered(prefab, what))
			{
				EffectManager.SpawnEffect(prefab, new EffectData
				{
					origin = centre,
					rotation = facing,
					scale = scale
				}, transmit);
			}
		}

		internal static void CasterFlash(CharacterBody body)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!CasterFlashOn || !Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList)
			{
				if (Object.op_Implicit((Object)(object)readOnlyInstances) && (Object)(object)readOnlyInstances.targetBody == (Object)(object)body)
				{
					ScreenFlash.PlayOn(readOnlyInstances, CasterFlashColor, CasterFlashPeak, CasterFlashRampIn, CasterFlashHold, CasterFlashFade, CasterFlashHdr);
				}
			}
		}
	}
	internal static class BundleVisuals
	{
		internal const string SlashMuzzle = "MuzzleSlash";

		internal const string FullBody = "FullBody, Override";

		internal const string Gesture = "Gesture, Override";

		internal const string EmptyState = "Empty";

		internal const string BufferEmptyState = "BufferEmpty";

		private static readonly string[] GestureLayers = new string[1] { "Gesture, Override" };

		private static readonly (string state, string clip, bool gesture, bool holds)[] SkillStates = new(string, string, bool, bool)[10]
		{
			("Slash1", "PhainonSlash1", true, false),
			("Slash2", "PhainonSlash2", true, false),
			("SlashBack", "PhainonSlashBack", true, false),
			("Slash1Chain", "PhainonSlash1Chain", true, false),
			("Sweep", "PhainonSweep", true, false),
			("Dash", "PhainonDash", false, false),
			("Execute", "PhainonExecute", false, false),
			("TransformStart", "PhainonTransformStart", false, true),
			("FormEnd", "PhainonFormEnd", false, true),
			("StageEntrance", "PhainonStageEntrance", false, true)
		};

		private static readonly (string state, string clip, bool holds)[] KhaslanaSkillStates = new(string, string, bool)[8]
		{
			("TransformReveal", "KhaslanaTransformReveal", true),
			("Bloodthorn1", "KhaslanaBloodthorn1", false),
			("Bloodthorn2", "KhaslanaBloodthorn2", false),
			("Soulscorch", "KhaslanaSoulscorch", false),
			("FlaresArrive", "KhaslanaFlaresArrive", false),
			("VerdictReady", "KhaslanaVerdictReady", true),
			("VerdictLoop", "KhaslanaVerdictLoop", true),
			("FinalHit", "KhaslanaFinalHit", true)
		};

		private static readonly string[] KhaslanaBodyStates = new string[9] { "Idle", "IdleCombat", "Run", "Sprint", "Jump", "BonusJump", "AscendDescend", "Hurt1", "Hurt2" };

		private static FormVisuals table;

		private static FormVisuals khaslanaTable;

		internal static IEnumerable<(string layer, string state)> ProbeStates => SkillStates.Select(((string state, string clip, bool gesture, bool holds) s) => (FullBody: "FullBody, Override", state: s.state)).Concat<(string, string)>(from s in SkillStates
			where s.gesture
			select (Gesture: "Gesture, Override", state: s.state)).Concat(new(string, string)[5]
		{
			("FullBody, Override", "Empty"),
			("Gesture, Override", "Empty"),
			("FullBody, Override", "BufferEmpty"),
			("Gesture, Override", "BufferEmpty"),
			("Body", "IdleCombat")
		});

		internal static IEnumerable<string> ProbeParameters => SkillStates.Select(((string state, string clip, bool gesture, bool holds) s) => RateParam(s.state));

		internal static IEnumerable<(string layer, string state)> KhaslanaProbeStates => KhaslanaSkillStates.Select(((string state, string clip, bool holds) s) => (FullBody: "FullBody, Override", state: s.state)).Concat(new(string, string)[6]
		{
			("FullBody, Override", "Empty"),
			("FullBody, Override", "BufferEmpty"),
			("Gesture, Override", "Empty"),
			("Gesture, Override", "BufferEmpty"),
			("AimPitch", "PitchControl"),
			("AimYaw", "YawControl")
		}).Concat<(string, string)>(KhaslanaBodyStates.Select((string s) => ("Body", s: s)));

		internal static IEnumerable<string> KhaslanaProbeParameters => KhaslanaSkillStates.Select(((string state, string clip, bool holds) s) => RateParam(s.state));

		internal static FormVisuals Table
		{
			get
			{
				if (table == null)
				{
					table = Build();
				}
				CopyPlaceholderSounds(table);
				return table;
			}
		}

		internal static FormVisuals KhaslanaTable
		{
			get
			{
				if (khaslanaTable == null)
				{
					khaslanaTable = BuildKhaslana();
				}
				CopyPlaceholderSounds(khaslanaTable);
				return khaslanaTable;
			}
		}

		internal static string RateParam(string state)
		{
			return state + ".playbackRate";
		}

		private static void CopyPlaceholderSounds(FormVisuals visuals)
		{
			FormVisuals formVisuals = PlaceholderVisuals.Table;
			visuals.slashSwingSound = formVisuals.slashSwingSound;
			visuals.slashHitSound = formVisuals.slashHitSound;
		}

		private static string SoundNote()
		{
			if (!PhainonSounds.BankLoaded)
			{
				return "Merc sounds (no PhainonBank)";
			}
			return "PhainonBank cues (Merc sounds unused)";
		}

		private static GameObject EffectOr(GameObject clone, GameObject placeholder)
		{
			if (!Object.op_Implicit((Object)(object)clone))
			{
				return placeholder;
			}
			return clone;
		}

		private static FormVisuals Build()
		{
			List<string> resolved = new List<string>();
			List<string> missing = new List<string>();
			AnimRef animRef = Skill("SlashBack");
			FormVisuals formVisuals = new FormVisuals
			{
				slashHitbox = "PhSlash",
				sweepHitbox = "PhSweep",
				bloodthornHitbox = "PhSlash",
				soulscorchHitbox = "PhSweep",
				slash1 = Skill("Slash1"),
				slash2 = (animRef.IsValid ? animRef : Skill("Slash2")),
				slash1Chain = (animRef.IsValid ? Skill("Slash1Chain") : default(AnimRef)),
				sweep = Skill("Sweep"),
				dash = Skill("Dash"),
				execute = Skill("Execute"),
				transformStart = Skill("TransformStart"),
				formEnd = Skill("FormEnd"),
				stageEntrance = Skill("StageEntrance"),
				transformReveal = default(AnimRef),
				slash1Muzzle = "MuzzleSlash",
				slash2Muzzle = "MuzzleSlash",
				slashSwingEffect = EffectOr(PhainonEffects.slashSwing, PlaceholderVisuals.Table.slashSwingEffect),
				slashHitEffect = EffectOr(PhainonEffects.slashHit, PlaceholderVisuals.Table.slashHitEffect),
				slashRibbon = ((Object)(object)PhainonEffects.slashRibbon != (Object)null)
			};
			Log.Info("Visuals: bundle rig table, skill states [" + string.Join(", ", resolved) + "]" + ((missing.Count > 0) ? (", not in animPhainon [" + string.Join(", ", missing) + "] (off)") : "") + "; release states [" + string.Join(", ", ReleaseStates(Has)) + "]; clip data " + (ClipData.Loaded ? (ClipData.Count + " clips") : "missing (fallback timings)") + "; " + (PhainonModel.HasKhaslanaRig ? "Khaslana refs on animKhaslana (KhaslanaTable)" : "Khaslana refs off (no KhaslanaRig)") + "; effects " + (formVisuals.slashRibbon ? ("blade ribbon (" + PhainonEffects.slashRibbonKind + ")") : NameOf(formVisuals.slashSwingEffect)) + "/" + NameOf(formVisuals.slashHitEffect) + ", " + SoundNote() + ", muzzle MuzzleSlash");
			return formVisuals;
			AnimRef Skill(string state)
			{
				var (text, clip, flag, holds) = SkillStates.First(((string state, string clip, bool gesture, bool holds) s) => s.state == state);
				if (!Has("FullBody, Override", text))
				{
					missing.Add(text);
					return default(AnimRef);
				}
				string text2 = RateParam(text);
				if (PhainonModel.ProbeHasParameter(text2) == false)
				{
					Log.Warning("Visuals: animPhainon has state " + text + " but no float '" + text2 + "'; playing it unscaled");
					text2 = null;
				}
				string[] array = ((flag && Has("Gesture, Override", text)) ? GestureLayers : null);
				resolved.Add((array != null) ? (text + "(+Gesture)") : text);
				return new AnimRef("FullBody, Override", text, text2, array, clip, holds);
			}
		}

		private static string NameOf(GameObject prefab)
		{
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return "<none>";
			}
			return ((Object)prefab).name;
		}

		private static FormVisuals BuildKhaslana()
		{
			List<string> resolved = new List<string>();
			List<string> missing = new List<string>();
			AnimRef animRef = Skill("Bloodthorn1");
			AnimRef animRef2 = Skill("Bloodthorn2");
			FormVisuals formVisuals = new FormVisuals
			{
				slashHitbox = "PhSlash",
				sweepHitbox = "PhSweep",
				bloodthornHitbox = "PhSlash",
				soulscorchHitbox = "PhSweep",
				slash1 = animRef,
				slash2 = animRef2,
				transformReveal = Skill("TransformReveal"),
				bloodthorn1 = animRef,
				bloodthorn2 = animRef2,
				soulscorch = Skill("Soulscorch"),
				flares = Skill("FlaresArrive"),
				stardeath = Skill("VerdictReady"),
				stardeathLoop = Skill("VerdictLoop"),
				finalHit = Skill("FinalHit"),
				slash1Muzzle = "MuzzleSlash",
				slash2Muzzle = "MuzzleSlash",
				slashSwingEffect = EffectOr(PhainonEffects.khaslanaSwing, PlaceholderVisuals.Table.slashSwingEffect),
				slashHitEffect = EffectOr(PhainonEffects.khaslanaHit, PlaceholderVisuals.Table.slashHitEffect),
				slashRibbon = ((Object)(object)PhainonEffects.slashRibbon != (Object)null)
			};
			Log.Info("Visuals: Khaslana table (animKhaslana), skill states [" + string.Join(", ", resolved) + "]" + ((missing.Count > 0) ? (", not in animKhaslana [" + string.Join(", ", missing) + "] (off)") : "") + "; release states [" + string.Join(", ", ReleaseStates(HasKhaslana)) + "]; slash1/slash2 = Bloodthorn1/Bloodthorn2; effects " + (formVisuals.slashRibbon ? ("blade ribbon (" + PhainonEffects.slashRibbonKind + ")") : NameOf(formVisuals.slashSwingEffect)) + "/" + NameOf(formVisuals.slashHitEffect) + ", " + SoundNote() + ", muzzle MuzzleSlash");
			return formVisuals;
			AnimRef Skill(string state)
			{
				var (text, clip, flag) = KhaslanaSkillStates.First(((string state, string clip, bool holds) s) => s.state == state);
				if (!HasKhaslana("FullBody, Override", text))
				{
					missing.Add(text);
					return default(AnimRef);
				}
				string text2 = RateParam(text);
				if (PhainonModel.ProbeHasKhaslanaParameter(text2) == false)
				{
					Log.Warning("Visuals: animKhaslana has state " + text + " but no float '" + text2 + "'; playing it unscaled");
					text2 = null;
				}
				ClipInfo info;
				ClipInfo clipInfo = (ClipData.TryGet(clip, out info) ? info : null);
				resolved.Add(text + (flag ? "(holds)" : "") + ((clipInfo == null) ? "(no clip data)" : (clipInfo.hideWeapon ? "(weapon hide)" : "")));
				return new AnimRef("FullBody, Override", text, text2, null, clip, flag);
			}
		}

		private static bool Has(string layer, string state)
		{
			return PhainonModel.ProbeHasState(layer, state) == true;
		}

		private static bool HasKhaslana(string layer, string state)
		{
			return PhainonModel.ProbeHasKhaslanaState(layer, state) == true;
		}

		internal static string ReleaseState(string layer)
		{
			return ReleaseState(layer, Has);
		}

		private static string ReleaseState(string layer, Func<string, string, bool> has)
		{
			if (!has(layer, "BufferEmpty"))
			{
				if (!has(layer, "Empty"))
				{
					return null;
				}
				return "Empty";
			}
			return "BufferEmpty";
		}

		internal static string ReleaseStateOn(Animator animator, string layerName)
		{
			int layer = (Object.op_Implicit((Object)(object)animator) ? animator.GetLayerIndex(layerName) : (-1));
			if (layer < 0)
			{
				return null;
			}
			if (!HasLive("BufferEmpty"))
			{
				if (!HasLive("Empty"))
				{
					return null;
				}
				return "Empty";
			}
			return "BufferEmpty";
			bool HasLive(string state)
			{
				if (!animator.HasState(layer, Animator.StringToHash(state)))
				{
					return animator.HasState(layer, Animator.StringToHash(layerName + "." + state));
				}
				return true;
			}
		}

		private static IEnumerable<string> ReleaseStates(Func<string, string, bool> has)
		{
			return new string[2] { "FullBody, Override", "Gesture, Override" }.Select((string layer) => layer + "/" + (ReleaseState(layer, has) ?? "<none>"));
		}
	}
	internal enum CameraAnchor
	{
		Rig,
		Ground
	}
	internal sealed class CameraTrack
	{
		internal string name;

		internal float start;

		internal float dt;

		internal CameraAnchor anchor;

		internal Vector3[] positions;

		internal Quaternion[] rotations;

		internal float[] fovs;

		internal float End => start + dt * (float)(positions.Length - 1);

		internal void Sample(float clipTime, out Vector3 position, out Quaternion rotation, out float fov)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0071: 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_0083: 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)
			int num = positions.Length - 1;
			float num2 = Mathf.Clamp((clipTime - start) / dt, 0f, (float)num);
			int num3 = Mathf.Min((int)num2, Mathf.Max(0, num - 1));
			int num4 = Mathf.Min(num3 + 1, num);
			float num5 = num2 - (float)num3;
			position = Vector3.LerpUnclamped(positions[num3], positions[num4], num5);
			rotation = Quaternion.SlerpUnclamped(rotations[num3], rotations[num4], num5);
			fov = Mathf.LerpUnclamped(fovs[num3], fovs[num4], num5);
		}
	}
	internal static class CameraTracks
	{
		internal const string FileName = "phainon_cameras.json";

		internal const string TransformClose = "TransformClose";

		internal const string TransformOrbit = "TransformOrbit";

		internal const string TransformHero = "TransformHero";

		internal const string FinalHitGround = "FinalHitGround";

		internal const string FinalHitClose = "FinalHitClose";

		internal const string FormEndFront = "FormEndFront";

		private const float AuthoredStep = 1f / 30f;

		private static readonly Dictionary<string, CameraTrack> tracks = new Dictionary<string, CameraTrack>(StringComparer.Ordinal);

		internal static bool Loaded => tracks.Count > 0;

		internal static IEnumerable<CameraTrack> All => tracks.Values;

		internal static bool TryGet(string name, out CameraTrack track)
		{
			track = null;
			if (name != null)
			{
				return tracks.TryGetValue(name, out track);
			}
			return false;
		}

		internal static void Load()
		{
			tracks.Clear();
			string path = Path.Combine(Asset.pluginDirectory ?? "", "phainon_cameras.json");
			if (!File.Exists(path))
			{
				Log.Info("Asset: no phainon_cameras.json; the transform and Final Hit keep the normal camera (run tools/anim/camtrack.py)");
				return;
			}
			try
			{
				Parse(File.ReadAllText(path));
				BuildFormEndFront();
				List<string> list = new List<string>();
				foreach (CameraTrack value in tracks.Values)
				{
					list.Add($"{value.name} {value.start:0.###}-{value.End:0.###} s ({value.positions.Length}, {value.anchor})");
				}
				Log.Info("Asset: camera tracks " + string.Join(", ", list));
			}
			catch (Exception ex)
			{
				tracks.Clear();
				Log.Error("Asset: phainon_cameras.json could not be parsed (" + ex.GetType().Name + ": " + ex.Message + "); the cinematics keep the normal camera");
			}
		}

		internal static void BuildFormEndFront()
		{
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			if (!Loaded)
			{
				return;
			}
			float num = Mathf.Max(1f / 30f, CinematicFx.FormEndShotSettleAt);
			float num2 = Mathf.Max(num + 1f / 30f, CinematicFx.FormEndShotEndAt);
			float num3 = (CinematicFx.FormEndShotEndDistance - CinematicFx.FormEndShotDistance) / (num2 - num);
			int num4 = Mathf.CeilToInt(num2 / (1f / 30f) - 0.001f) + 1;
			CameraTrack cameraTrack = new CameraTrack
			{
				name = "FormEndFront",
				start = 0f,
				dt = 1f / 30f,
				anchor = CameraAnchor.Rig,
				positions = (Vector3[])(object)new Vector3[num4],
				rotations = (Quaternion[])(object)new Quaternion[num4],
				fovs = new float[num4]
			};
			Vector3 val = default(Vector3);
			for (int i = 0; i < num4; i++)
			{
				float num5 = (float)i * (1f / 30f);
				float num6;
				float num7;
				float num8;
				if (num5 < num)
				{
					float u = num5 / num;
					num6 = Hermite(CinematicFx.FormEndShotStartDistance, CinematicFx.FormEndShotDistance, 1.5f, num3 * num, u);
					num7 = Hermite(CinematicFx.FormEndShotStartHeight, CinematicFx.FormEndShotHeight, 0f, 0f, u);
					num8 = Hermite(CinematicFx.FormEndShotStartAim, CinematicFx.FormEndShotAim, 0f, 0f, u);
				}
				else
				{
					num6 = CinematicFx.FormEndShotDistance + num3 * Mathf.Min(num5 - num, num2 - num);
					num7 = CinematicFx.FormEndShotHeight;
					num8 = CinematicFx.FormEndShotAim;
				}
				((Vector3)(ref val))..ctor(CinematicFx.FormEndShotSide, num7, num6);
				Vector3 val2 = new Vector3(0f, num8, 0f) - val;
				cameraTrack.positions[i] = val;
				cameraTrack.rotations[i] = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? Quaternion.LookRotation(val2, Vector3.up) : Quaternion.identity);
				cameraTrack.fovs[i] = CinematicFx.FormEndShotFov;
			}
			tracks["FormEndFront"] = cameraTrack;
		}

		private static float Hermite(float from, float to, float startSpeed, float endSlope, float u)
		{
			float num = u * u;
			float num2 = num * u;
			return (2f * num2 - 3f * num + 1f) * from + (num2 - 2f * num + u) * startSpeed * (to - from) + (-2f * num2 + 3f * num) * to + (num2 - num) * endSlope;
		}

		private static void Parse(string json)
		{
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			if (!(ClipData.MiniJson.Parse(json) is Dictionary<string, object> dictionary) || !dictionary.TryGetValue("tracks", out var value) || !(value is Dictionary<string, object> dictionary2))
			{
				throw new FormatException("expected {\"tracks\": {...}}");
			}
			foreach (KeyValuePair<string, object> item in dictionary2)
			{
				if (!(item.Value is Dictionary<string, object> dictionary3) || !dictionary3.TryGetValue("frames", out var value2) || !(value2 is List<object> { Count: not 0 } list))
				{
					throw new FormatException("track " + item.Key + ": no frames");
				}
				object value3;
				CameraTrack cameraTrack = new CameraTrack
				{
					name = item.Key,
					start = Number(dictionary3, "start"),
					dt = Number(dictionary3, "dt"),
					anchor = ((dictionary3.TryGetValue("anchor", out value3) && value3 as string == "ground") ? CameraAnchor.Ground : CameraAnchor.Rig),
					positions = (Vector3[])(object)new Vector3[list.Count],
					rotations = (Quaternion[])(object)new Quaternion[list.Count],
					fovs = new float[list.Count]
				};
				if (!(cameraTrack.dt > 0f))
				{
					throw new FormatException($"track {item.Key}: dt {cameraTrack.dt}");
				}
				for (int i = 0; i < list.Count; i++)
				{
					if (!(list[i] is List<object> { Count: >=8 } list2))
					{
						throw new FormatException($"track {item.Key}: frame {i} is not [x, y, z, qx, qy, qz, qw, fov]");
					}
					cameraTrack.positions[i] = new Vector3(F(list2[0]), F(list2[1]), F(list2[2]));
					cameraTrack.rotations[i] = Quaternion.Normalize(new Quaternion(F(list2[3]), F(list2[4]), F(list2[5]), F(list2[6])));
					cameraTrack.fovs[i] = F(list2[7]);
				}
				tracks[item.Key] = cameraTrack;
			}
		}

		private static float Number(Dictionary<string, object> entry, string key)
		{
			if (!entry.TryGetValue(key, out var value) || !(value is double num))
			{
				throw new FormatException("no number '" + key + "'");
			}
			return (float)num;
		}

		private static float F(object value)
		{
			if (!(value is double num))
			{
				throw new FormatException($"not a number: {value}");
			}
			return (float)num;
		}
	}
	internal struct ClipMark
	{
		public float time;

		public string tag;

		public ClipMark(float time, string tag)
		{
			this.time = time;
			this.tag = tag;
		}
	}
	internal struct MotionSample
	{
		public float dx;

		public float dz;

		public float yaw;

		public Vector3 Planar => new Vector3(dx, 0f, dz);

		public MotionSample(float dx, float dz, float yaw)
		{
			this.dx = dx;
			this.dz = dz;
			this.yaw = yaw;
		}
	}
	internal sealed class ClipMotion
	{
		public string source;

		public float length;

		public readonly List<float> times = new List<float>();

		public readonly List<MotionSample> samples = new List<MotionSample>();

		public Vector2 Net { get; internal set; }

		public MotionSample DisplacementAt(float t)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			int count = times.Count;
			if (count == 0)
			{
				float num = ((length > 0f) ? Mathf.Clamp01(t / length) : 1f);
				return new MotionSample(Net.x * num, Net.y * num, 0f);
			}
			if (t <= times[0])
			{
				return samples[0];
			}
			if (t >= times[count - 1])
			{
				return samples[count - 1];
			}
			int num2 = 0;
			int num3 = count - 1;
			while (num3 - num2 > 1)
			{
				int num4 = (num2 + num3) / 2;
				if (times[num4] <= t)
				{
					num2 = num4;
				}
				else
				{
					num3 = num4;
				}
			}
			float num5 = times[num3] - times[num2];
			float num6 = ((num5 > 0f) ? ((t - times[num2]) / num5) : 0f);
			MotionSample motionSample = samples[num2];
			MotionSample motionSample2 = samples[num3];
			float yaw = ((Mathf.Abs(motionSample2.yaw - motionSample.yaw) > 180f) ? Mathf.LerpAngle(motionSample.yaw, motionSample2.yaw, num6) : Mathf.Lerp(motionSample.yaw, motionSample2.yaw, num6));
			return new MotionSample(Mathf.Lerp(motionSample.dx, motionSample2.dx, num6), Mathf.Lerp(motionSample.dz, motionSample2.dz, num6), yaw);
		}

		public MotionSample Delta(float from, float to)
		{
			MotionSample motionSample = DisplacementAt(from);
			MotionSample motionSample2 = DisplacementAt(to);
			return new MotionSample(motionSample2.dx - motionSample.dx, motionSample2.dz - motionSample.dz, motionSample2.yaw - motionSample.yaw);
		}
	}
	internal sealed class ClipInfo
	{
		public string name;

		public float length;

		public float frameRate = 60f;

		public bool loop;

		public string source;

		public Vector2? trim;

		public readonly List<ClipMark> hits = new List<ClipMark>();

		public readonly List<ClipMark> events = new List<ClipMark>();

		public ClipMotion motion;

		public string weapon = "clip";

		public bool hideWeapon => string.Equals(weapon, "hide", StringComparison.OrdinalIgnoreCase);

		public float HitTime(string tag, float fallback)
		{
			foreach (ClipMark hit in hits)
			{
				if (hit.tag == tag)
				{
					return hit.time;
				}
			}
			return fallback;
		}

		public List<float> HitTimes(string tag)
		{
			List<float> list = new List<float>();
			foreach (ClipMark hit in hits)
			{
				if (hit.tag == tag)
				{
					list.Add(hit.time);
				}
			}
			list.Sort();
			return list;
		}

		public float HitFraction(string tag, float fallbackFraction)
		{
			if (length <= 0f)
			{
				return fallbackFraction;
			}
			float num = HitTime(tag, float.NaN);
			if (!float.IsNaN(num))
			{
				return Mathf.Clamp01(num / length);
			}
			return fallbackFraction;
		}

		public override string ToString()
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(string.Format("{0}: {1:0.####} s @ {2:0} fps{3}", name, length, frameRate, loop ? ", loop" : ""));
			if (hits.Count > 0)
			{
				stringBuilder.Append(", hits [");
				for (int i = 0; i < hits.Count; i++)
				{
					stringBuilder.Append((i > 0) ? ", " : "").Append($"{hits[i].tag} {hits[i].time:0.####}");
				}
				stringBuilder.Append("]");
			}
			if (events.Count > 0)
			{
				stringBuilder.Append($", {events.Count} event(s)");
			}
			if (hideWeapon)
			{
				stringBuilder.Append(", weapon hide");
			}
			if (motion != null)
			{
				stringBuilder.Append($", motion net ({motion.Net.x:0.###}, {motion.Net.y:0.###}) m over {motion.times.Count} frames");
			}
			return stringBuilder.ToString();
		}
	}
	internal static class ClipData
	{
		internal sealed class MiniJson
		{
			private readonly string text;

			private int pos;

			private MiniJson(string text)
			{
				this.text = text ?? "";
			}

			internal static object Parse(string text)
			{
				MiniJson miniJson = new MiniJson(text);
				if (miniJson.text.Length > 0 && miniJson.text[0] == '\ufeff')
				{
					miniJson.pos = 1;
				}
				object result = miniJson.ReadValue();
				miniJson.SkipWhitespace();
				if (miniJson.pos != miniJson.text.Length)
				{
					throw miniJson.Error("trailing characters");
				}
				return result;
			}

			private FormatException Error(string message)
			{
				return new FormatException($"JSON: {message} at offset {pos}");
			}

			private void SkipWhitespace()
			{
				while (pos < text.Length && (text[pos] == ' ' || text[pos] == '\t' || text[pos] == '\n' || text[pos] == '\r'))
				{
					pos++;
				}
			}

			private object ReadValue()
			{
				SkipWhitespace();
				if (pos >= text.Length)
				{
					throw Error("unexpected end");
				}
				char c = text[pos];
				switch (c)
				{
				case '{':
					return ReadObject();
				case '[':
					return ReadArray();
				case '"':
					return ReadString();
				case 't':
					Expect("true");
					return true;
				case 'f':
					Expect("false");
					return false;
				case 'n':
					Expect("null");
					return null;
				default:
					switch (c)
					{
					case '-':
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						return ReadNumber();
					default:
						switch (c)
						{
						case 'N':
							Expect("NaN");
							return double.NaN;
						case 'I':
							Expect("Infinity");
							return double.PositiveInfinity;
						default:
							throw Error($"unexpected '{c}'");
						}
					}
				}
			}

			private void Expect(string word)
			{
				if (string.CompareOrdinal(text, pos, word, 0, word.Length) != 0)
				{
					throw Error("expected '" + word + "'");
				}
				pos += word.Length;
			}

			private Dictionary<string, object> ReadObject()
			{
				Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
				pos++;
				SkipWhitespace();
				if (pos < text.Length && text[pos] == '}')
				{
					pos++;
					return dictionary;
				}
				while (true)
				{
					SkipWhitespace();
					if (pos >= text.Length || text[pos] != '"')
					{
						throw Error("expected a key");
					}
					string key = ReadString();
					SkipWhitespace();
					if (pos >= text.Length || text[pos] != ':')
					{
						throw Error("expected ':'");
					}
					pos++;
					dictionary[key] = ReadValue();
					SkipWhitespace();
					if (pos >= text.Length)
					{
						throw Error("unterminated object");
					}
					if (text[pos] != ',')
					{
						break;
					}
					pos++;
				}
				if (text[pos] == '}')
				{
					pos++;
					return dictionary;
				}
				throw Error("expected ',' or '}'");
			}

			private List<object> ReadArray()
			{
				List<object> list = new List<object>();
				pos++;
				SkipWhitespace();
				if (pos < text.Length && text[pos] == ']')
				{
					pos++;
					return list;
				}
				while (true)
				{
					list.Add(ReadValue());
					SkipWhitespace();
					if (pos >= text.Length)
					{
						throw Error("unterminated array");
					}
					if (text[pos] != ',')
					{
						break;
					}
					pos++;
				}
				if (text[pos] == ']')
				{
					pos++;
					return list;
				}
				throw Error("expected ',' or ']'");
			}

			private string ReadString()
			{
				pos++;
				StringBuilder stringBuilder = new StringBuilder();
				while (pos < text.Length)
				{
					char c = text[pos++];
					switch (c)
					{
					case '"':
						return stringBuilder.ToString();
					default:
						stringBuilder.Append(c);
						continue;
					case '\\':
						break;
					}
					if (pos >= text.Length)
					{
						break;
					}
					char c2 = text[pos++];
					switch (c2)
					{
					case '"':
						stringBuilder.Append('"');
						break;
					case '\\':
						stringBuilder.Append('\\');
						break;
					case '/':
						stringBuilder.Append('/');
						break;
					case 'b':
						stringBuilder.Append('\b');
						break;
					case 'f':
						stringBuilder.Append('\f');
						break;
					case 'n':
						stringBuilder.Append('\n');
						break;
					case 'r':
						stringBuilder.Append('\r');
						break;
					case 't':
						stringBuilder.Append('\t');
						break;
					case 'u':
					{
						if (pos + 4 > text.Length || !int.TryParse(text.Substring(pos, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
						{
							throw Error("bad \\u escape");
						}
						stringBuilder.Append((char)result);
						pos += 4;
						break;
					}
					default:
						throw Error($"bad escape '\\{c2}'");
					}
				}
				throw Error("unterminated string");
			}

			private double ReadNumber()
			{
				int num = pos;
				if (this.text[pos] == '-')
				{
					pos++;
				}
				while (pos < this.text.Length)
				{
					char c = this.text[pos];
					if ((c < '0' || c > '9') && c != '.' && c != 'e' && c != 'E' && c != '+' && c != '-')
					{
						break;
					}
					pos++;
				}
				string text = this.text.Substring(num, pos - num);
				if (text == "-" && string.CompareOrdinal(this.text, pos, "Infinity", 0, 8) == 0)
				{
					pos += 8;
					return double.NegativeInfinity;
				}
				if (!double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					throw Error("bad number '" + text + "'");
				}
				return result;
			}
		}

		internal const string AssetName = "PhainonClipData";

		private static readonly Dictionary<string, ClipInfo> clips = new Dictionary<string, ClipInfo>(StringComparer.Ordinal);

		internal static bool Loaded { get; private set; }

		internal static int Count => clips.Count;

		internal static IEnumerable<ClipInfo> All => clips.Values;

		internal static bool TryGet(string clip, out ClipInfo info)
		{
			info = null;
			if (!string.IsNullOrEmpty(clip))
			{
				return clips.TryGetValue(clip, out info);
			}
			return false;
		}

		internal static void Load()
		{
			clips.Clear();
			Loaded = false;
			if (!Object.op_Implicit((Object)(object)Asset.Bundle))
			{
				Log.Info("Asset: no phainon.bundle; no clip data (states use their fallback timings)");
				return;
			}
			if (!Asset.HasBundleAsset("PhainonClipData"))
			{
				Log.Warning("Asset: no PhainonClipData in phainon.bundle (bundle older than M4); states use their fallback timings");
				return;
			}
			TextAsset val = Asset.LoadBundleAsset<TextAsset>("PhainonClipData");
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			try
			{
				Parse(val.text);
				Loaded = true;
				Log.Info(string.Format("Asset: clip data {0} clips ({1})", clips.Count, string.Join(", ", clips.Keys)));
			}
			catch (Exception ex)
			{
				clips.Clear();
				Log.Error("Asset: PhainonClipData could not be parsed (" + ex.GetType().Name + ": " + ex.Message + "); states use their fallback timings");
			}
		}

		internal static void Parse(string json)
		{
			if (!(MiniJson.Parse(json) is Dictionary<string, object> dictionary) || !dictionary.TryGetValue("clips", out var value) || !(value is Dictionary<string, object> dictionary2))
			{
				throw new FormatException("expected {\"clips\": {...}}");
			}
			foreach (KeyValuePair<string, object> item in dictionary2)
			{
				if (!(item.Value is Dictionary<string, object> entry))
				{
					throw new FormatException("clip '" + item.Key + "' is not an object");
				}
				clips[item.Key] = ReadClip(item.Key, entry);
			}
		}

		private static ClipInfo ReadClip(string name, Dictionary<string, object> entry)
		{
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			ClipInfo obj = new ClipInfo
			{
				name = name,
				length = Number(entry, "length", 0f),
				frameRate = Number(entry, "frameRate", 60f)
			};
			bool flag = default(bool);
			int num;
			if (entry.TryGetValue("loop", out var value))
			{
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			obj.loop = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			obj.source = (entry.TryGetValue("source", out var value2) ? (value2 as string) : null);
			obj.weapon = ((entry.TryGetValue("weapon", out var value3) && value3 is string { Length: >0 } text) ? text : "clip");
			ClipInfo clipInfo = obj;
			if (clipInfo.length <= 0f)
			{
				throw new FormatException("clip '" + name + "' has no positive length");
			}
			if (entry.TryGetValue("trim", out var value4) && value4 is Dictionary<string, object> obj2)
			{
				clipInfo.trim = new Vector2(Number(obj2, "start", 0f), Number(obj2, "end", 0f));
			}
			ReadMarks(entry, "hits", clipInfo.hits, name);
			ReadMarks(entry, "events", clipInfo.events, name);
			if (entry.TryGetValue("motion", out var value5) && value5 is Dictionary<string, object> obj3)
			{
				clipInfo.motion = ReadMotion(obj3, clipInfo.length);
			}
			return clipInfo;
		}

		private static void ReadMarks(Dictionary<string, object> entry, string key, List<ClipMark> into, string clip)
		{
			if (!entry.TryGetValue(key, out var value) || !(value is List<object> list))
			{
				return;
			}
			foreach (object item in list)
			{
				if (item is List<object> { Count: >=2 } list2 && list2[0] is double num && list2[1] is string tag)
				{
					into.Add(new ClipMark((float)num, tag));
					continue;
				}
				if (item is Dictionary<string, object> dictionary && dictionary.TryGetValue("tag", out var value2) && value2 is string tag2)
				{
					into.Add(new ClipMark(Number(dictionary, "t", Number(dictionary, "time", 0f)), tag2));
					continue;
				}
				throw new FormatException("clip '" + clip + "': bad " + key + " item");
			}
			into.Sort((ClipMark a, ClipMark b) => a.time.CompareTo(b.time));
		}

		private static ClipMotion ReadMotion(Dictionary<string, object> obj, float clipLength)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			object value;
			ClipMotion clipMotion = new ClipMotion
			{
				source = (obj.TryGetValue("source", out value) ? (value as string) : null),
				length = Number(obj, "length", clipLength)
			};
			if (obj.TryGetValue("net", out var value2) && value2 is List<object> { Count: >=2 } list && list[0] is double num && list[1] is double num2)
			{
				clipMotion.Net = new Vector2((float)num, (float)num2);
			}
			if (obj.TryGetValue("frames", out var value3) && value3 is List<object> list2)
			{
				List<KeyValuePair<float, MotionSample>> list3 = new List<KeyValuePair<float, MotionSample>>(list2.Count);
				foreach (object item in list2)
				{
					if (item is Dictionary<string, object> obj2)
					{
						list3.Add(new KeyValuePair<float, MotionSample>(Number(obj2, "t", 0f), new MotionSample(Number(obj2, "dx", 0f), Number(obj2, "dz", 0f), Number(obj2, "yaw", 0f))));
					}
				}
				list3.Sort((KeyValuePair<float, MotionSample> a, KeyValuePair<float, MotionSample> b) => a.Key.CompareTo(b.Key));
				foreach (KeyValuePair<float, MotionSample> item2 in list3)
				{
					clipMotion.times.Add(item2.Key);
					clipMotion.samples.Add(item2.Value);
				}
				if (value2 == null && clipMotion.samples.Count > 0)
				{
					MotionSample motionSample = clipMotion.samples[clipMotion.samples.Count - 1];
					clipMotion.Net = new Vector2(motionSample.dx, motionSample.dz);
				}
			}
			return clipMotion;
		}

		private static float Number(Dictionary<string, object> obj, string key, float fallback)
		{
			if (!obj.TryGetValue(key, out var value) || !(value is double num))
			{
				return fallback;
			}
			return (float)num;
		}
	}
	internal static class ClothShared
	{
		internal class Tuning
		{
			internal float damping;

			internal float elasticity;

			internal float stiffness;

			internal float inert;

			internal float endLength;

			internal float radius;

			public override string ToString()
			{
				return $"damping {damping:0.###} elasticity {elasticity:0.###} stiffness {stiffness:0.###} inert {inert:0.###} " + $"endLength {endLength:0.##} radius {radius:0.###}";
			}
		}

		internal static void Write(DynamicBone bone, Tuning t, float radius)
		{
			bone.m_Damping = Mathf.Clamp01(t.damping);
			bone.m_Elasticity = Mathf.Clamp01(t.elasticity);
			bone.m_Stiffness = Mathf.Clamp01(t.stiffness);
			bone.m_Inert = Mathf.Clamp01(t.inert);
			bone.m_EndLength = Mathf.Max(0f, t.endLength);
			bone.m_Radius = Mathf.Max(0f, radius);
		}

		internal static DynamicBone AddChain(GameObject host, Transform chainRoot, List<DynamicBoneCollider> capsules)
		{
			DynamicBone obj = host.AddComponent<DynamicBone>();
			obj.m_Root = chainRoot;
			obj.m_Colliders = ((capsules != null) ? new List<DynamicBoneCollider>(capsules) : new List<DynamicBoneCollider>());
			obj.m_Exclusions = new List<Transform>();
			return obj;
		}

		internal static List<DynamicBoneCollider> AddLegCapsules(Transform rig, Transform rootBone, (string bone, string child, float radius)[] segments, List<string> missing)
		{
			//IL_0072: 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)
			List<DynamicBoneCollider> list = new List<DynamicBoneCollider>();
			for (int i = 0; i < segments.Length; i++)
			{
				(string bone, string child, float radius) tuple = segments[i];
				string item = tuple.bone;
				string item2 = tuple.child;
				float item3 = tuple.radius;
				Transform val = Prefabs.FindDeep(rootBone, item);
				Transform val2 = (Object.op_Implicit((Object)(object)val) ? val.Find(item2) : null);
				if (!Object.op_Implicit((Object)(object)val2))
				{
					missing.Add(item + "->" + item2);
				}
				else
				{
					list.Add(AddCapsule(val, val2, item3 * rig.lossyScale.x / val.lossyScale.x));
				}
			}
			return list;
		}

		private static DynamicBoneCollider AddCapsule(Transform bone, Transform child, float localRadius)
		{
			//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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0043: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 localPosition = child.localPosition;
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(Mathf.Abs(localPosition.x), Mathf.Abs(localPosition.y), Mathf.Abs(localPosition.z));
			int num = ((!(val.x >= val.y) || !(val.x >= val.z)) ? ((val.y >= val.z) ? 1 : 2) : 0);
			DynamicBoneCollider obj = ((Component)bone).gameObject.AddComponent<DynamicBoneCollider>();
			obj.m_Direction = (Direction)num;
			obj.m_Center = localPosition * 0.5f;
			obj.m_Radius = localRadius;
			obj.m_Height = ((Vector3)(ref val))[num] + 2f * localRadius;
			return obj;
		}

		internal static float Gap(Vector3 point, float particleRadius, List<DynamicBoneCollider> capsules, out string capsuleName)
		{
			//IL_002a: 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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			float num = float.PositiveInfinity;
			capsuleName = "none";
			foreach (DynamicBoneCollider capsule in capsules)
			{
				CapsuleWorld(capsule, out var a, out var b, out var radius);
				float num2 = DistanceToSegment(point, a, b) - radius - particleRadius;
				if (num2 < num)
				{
					num = num2;
					capsuleName = ((Object)capsule).name;
				}
			}
			return num;
		}

		private static void CapsuleWorld(DynamicBoneCollider capsule, out Vector3 a, out Vector3 b, out float radius)
		{
			//IL_000f: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected I4, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0065: 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_0072: 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)
			Transform transform = ((Component)capsule).transform;
			radius = capsule.m_Radius * Mathf.Abs(transform.lossyScale.x);
			float num = Mathf.Max(0f, capsule.m_Height * 0.5f - capsule.m_Radius);
			Vector3 zero = Vector3.zero;
			((Vector3)(ref zero))[(int)capsule.m_Direction] = num;
			a = transform.TransformPoint(capsule.m_Center - zero);
			b = transform.TransformPoint(capsule.m_Center + zero);
		}

		private static float DistanceToSegment(Vector3 p, Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = b - a;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			float num = ((sqrMagnitude >