Decompiled source of ForgeVisual v0.1.0

ForgeVisual.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP;
using CharacterDestruction;
using Enemies;
using FX_EffectSystem;
using ForgeCore;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using Player;
using RootMotion.FinalIK;
using SNetwork;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ForgeVisual")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+66ec6b43e1a1603bac84a4b9a226674300b2fc7d")]
[assembly: AssemblyProduct("ForgeVisual")]
[assembly: AssemblyTitle("ForgeVisual")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ForgeVisual
{
	public enum BodyBone
	{
		Hips = 0,
		LeftUpperLeg = 1,
		RightUpperLeg = 2,
		LeftLowerLeg = 3,
		RightLowerLeg = 4,
		LeftFoot = 5,
		RightFoot = 6,
		Spine = 7,
		Chest = 8,
		Neck = 9,
		Head = 10,
		LeftShoulder = 11,
		RightShoulder = 12,
		LeftUpperArm = 13,
		RightUpperArm = 14,
		LeftLowerArm = 15,
		RightLowerArm = 16,
		LeftHand = 17,
		RightHand = 18,
		LeftToes = 19,
		RightToes = 20,
		UpperChest = 54
	}
	public enum BodyMeasure
	{
		ShoulderSpan,
		LeftLeg,
		RightLeg,
		LeftArm,
		RightArm
	}
	public readonly struct WearBone
	{
		public string Model { get; }

		public BodyBone Body { get; }

		public bool Worn { get; }

		public BodyMeasure Scale { get; }

		public WearBone(string model, BodyBone body, bool worn = true, BodyMeasure scale = BodyMeasure.ShoulderSpan)
		{
			Model = model ?? throw new ArgumentNullException("model");
			Body = body;
			Worn = worn;
			Scale = scale;
		}
	}
	public readonly struct PoseLink
	{
		public string Model { get; }

		public BodyBone Body { get; }

		public BodyBone? BodyAlt { get; }

		public int Toward { get; }

		public int From { get; }

		public BodyBone? TowardBody { get; }

		public BodyBone? TowardBodyAlt { get; }

		public PoseLink(string model, BodyBone body, int toward = -1, int from = -1, BodyBone? bodyAlt = null, BodyBone? towardBody = null, BodyBone? towardBodyAlt = null)
		{
			Model = model ?? throw new ArgumentNullException("model");
			Body = body;
			Toward = toward;
			From = from;
			BodyAlt = bodyAlt;
			TowardBody = towardBody;
			TowardBodyAlt = towardBodyAlt;
		}
	}
	public readonly struct PoseReach
	{
		public int Upper { get; }

		public int Lower { get; }

		public int End { get; }

		public int Anchor { get; }

		public PoseReach(int upper, int lower, int end, int anchor)
		{
			Upper = upper;
			Lower = lower;
			End = end;
			Anchor = anchor;
		}
	}
	internal readonly struct RestPose
	{
		internal Vector3 Position { get; }

		internal Quaternion Rotation { get; }

		internal float Scale { get; }

		internal RestPose(Vector3 position, Quaternion rotation, float scale = 1f)
		{
			Position = position;
			Rotation = rotation;
			Scale = scale;
		}
	}
	internal struct Weights4
	{
		internal int I0 { get; set; }

		internal int I1 { get; set; }

		internal int I2 { get; set; }

		internal int I3 { get; set; }

		internal float W0 { get; set; }

		internal float W1 { get; set; }

		internal float W2 { get; set; }

		internal float W3 { get; set; }
	}
	internal static class BodyMath
	{
		internal static Quaternion LookRotation(Vector3 forward, Vector3 up)
		{
			if (forward.LengthSquared() < 1E-12f)
			{
				return Quaternion.Identity;
			}
			Vector3 vector = Vector3.Normalize(forward);
			Vector3 value = Vector3.Cross(up, vector);
			if (value.LengthSquared() < 1E-12f)
			{
				value = Vector3.Cross((Math.Abs(vector.Y) < 0.99f) ? Vector3.UnitY : Vector3.UnitX, vector);
			}
			value = Vector3.Normalize(value);
			Vector3 vector2 = Vector3.Cross(vector, value);
			return Quaternion.Normalize(Quaternion.CreateFromRotationMatrix(new Matrix4x4(value.X, value.Y, value.Z, 0f, vector2.X, vector2.Y, vector2.Z, 0f, vector.X, vector.Y, vector.Z, 0f, 0f, 0f, 0f, 1f)));
		}

		internal static Quaternion FromTo(Vector3 from, Vector3 to)
		{
			if (from.LengthSquared() < 1E-12f || to.LengthSquared() < 1E-12f)
			{
				return Quaternion.Identity;
			}
			Vector3 vector = Vector3.Normalize(from);
			Vector3 vector2 = Vector3.Normalize(to);
			float num = Vector3.Dot(vector, vector2);
			if (num >= 0.999999f)
			{
				return Quaternion.Identity;
			}
			if (num <= -0.999999f)
			{
				Vector3 value = Vector3.Cross(Vector3.UnitX, vector);
				if (value.LengthSquared() < 1E-06f)
				{
					value = Vector3.Cross(Vector3.UnitY, vector);
				}
				return Quaternion.CreateFromAxisAngle(Vector3.Normalize(value), (float)Math.PI);
			}
			return Quaternion.Normalize(new Quaternion(Vector3.Cross(vector, vector2), 1f + num));
		}

		internal static Vector3 Rotate(Quaternion q, Vector3 v)
		{
			return Vector3.Transform(v, q);
		}

		internal static Quaternion SkeletonFrame(Vector3 leftArm, Vector3 rightArm, Vector3 hips)
		{
			Vector3 vector = Vector3.Normalize(rightArm - leftArm);
			Vector3 vector2 = (leftArm + rightArm) * 0.5f - hips;
			Vector3 vector3 = Vector3.Normalize(Vector3.Cross(vector, vector2));
			vector2 = Vector3.Cross(vector3, vector);
			return LookRotation(vector3, vector2);
		}

		internal static Quaternion BoneFrame(Vector3 along)
		{
			if (along.LengthSquared() < 1E-08f)
			{
				return Quaternion.Identity;
			}
			along = Vector3.Normalize(along);
			return LookRotation(along, (Math.Abs(Vector3.Dot(along, Vector3.UnitZ)) > 0.8f) ? Vector3.UnitY : Vector3.UnitZ);
		}
	}
	internal static class WearSolver
	{
		internal static int[] Children(int[] parents)
		{
			int[] array = new int[parents.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = -1;
			}
			for (int j = 0; j < parents.Length; j++)
			{
				int num = parents[j];
				if (num >= 0)
				{
					array[num] = ((array[num] == -1) ? j : (-2));
				}
			}
			for (int k = 0; k < array.Length; k++)
			{
				if (array[k] == -2)
				{
					array[k] = -1;
				}
			}
			return array;
		}

		internal static string? Solve(IReadOnlyList<WearBone> bones, int[] parents, RestPose[] model, RestPose?[] game, out Quaternion[] offset, out float[] scale)
		{
			int count = bones.Count;
			offset = new Quaternion[count];
			scale = new float[count];
			for (int i = 0; i < count; i++)
			{
				offset[i] = Quaternion.Identity;
				scale[i] = 1f;
			}
			int num = IndexOf(bones, BodyBone.LeftUpperArm);
			int num2 = IndexOf(bones, BodyBone.RightUpperArm);
			int num3 = IndexOf(bones, BodyBone.Hips);
			if (num < 0 || num2 < 0 || num3 < 0 || !game[num].HasValue || !game[num2].HasValue || !game[num3].HasValue)
			{
				return "the bones must list LeftUpperArm, RightUpperArm and Hips, each on the game's body, to match the skeletons";
			}
			Quaternion value = BodyMath.SkeletonFrame(model[num].Position, model[num2].Position, model[num3].Position);
			Quaternion quaternion = BodyMath.SkeletonFrame(game[num].Value.Position, game[num2].Value.Position, game[num3].Value.Position) * Quaternion.Inverse(value);
			float span = (game[num2].Value.Position - game[num].Value.Position).Length() / Math.Max(0.0001f, (model[num2].Position - model[num].Position).Length());
			int[] array = Children(parents);
			for (int j = 0; j < count; j++)
			{
				RestPose? restPose = game[j];
				if (!restPose.HasValue)
				{
					continue;
				}
				RestPose valueOrDefault = restPose.GetValueOrDefault();
				if (!bones[j].Worn)
				{
					continue;
				}
				scale[j] = Measure(bones, model, game, bones[j].Scale, span);
				Vector3 v = Vector3.Zero;
				Vector3 to = Vector3.Zero;
				if (array[j] >= 0)
				{
					restPose = game[array[j]];
					if (restPose.HasValue)
					{
						RestPose valueOrDefault2 = restPose.GetValueOrDefault();
						v = model[array[j]].Position - model[j].Position;
						to = valueOrDefault2.Position - valueOrDefault.Position;
						goto IL_02b4;
					}
				}
				if (parents[j] >= 0)
				{
					restPose = game[parents[j]];
					if (restPose.HasValue)
					{
						RestPose valueOrDefault3 = restPose.GetValueOrDefault();
						v = model[j].Position - model[parents[j]].Position;
						to = valueOrDefault.Position - valueOrDefault3.Position;
					}
				}
				goto IL_02b4;
				IL_02b4:
				Quaternion quaternion2 = quaternion * model[j].Rotation;
				if (v.LengthSquared() > 1E-08f && to.LengthSquared() > 1E-08f)
				{
					quaternion2 = BodyMath.FromTo(BodyMath.Rotate(quaternion, v), to) * quaternion2;
				}
				offset[j] = Quaternion.Inverse(valueOrDefault.Rotation) * quaternion2;
			}
			return null;
		}

		internal static float Measure(IReadOnlyList<WearBone> bones, RestPose[] model, RestPose?[] game, BodyMeasure measure, float span)
		{
			return measure switch
			{
				BodyMeasure.LeftLeg => Chain(bones, model, game, span, BodyBone.LeftUpperLeg, BodyBone.LeftLowerLeg, BodyBone.LeftFoot), 
				BodyMeasure.RightLeg => Chain(bones, model, game, span, BodyBone.RightUpperLeg, BodyBone.RightLowerLeg, BodyBone.RightFoot), 
				BodyMeasure.LeftArm => Chain(bones, model, game, span, BodyBone.LeftUpperArm, BodyBone.LeftLowerArm, BodyBone.LeftHand), 
				BodyMeasure.RightArm => Chain(bones, model, game, span, BodyBone.RightUpperArm, BodyBone.RightLowerArm, BodyBone.RightHand), 
				_ => span, 
			};
		}

		private static float Chain(IReadOnlyList<WearBone> bones, RestPose[] model, RestPose?[] game, float fallback, BodyBone a, BodyBone b, BodyBone c)
		{
			int num = IndexOf(bones, a);
			int num2 = IndexOf(bones, b);
			int num3 = IndexOf(bones, c);
			if (num >= 0 && num2 >= 0 && num3 >= 0)
			{
				RestPose? restPose = game[num];
				if (restPose.HasValue)
				{
					RestPose valueOrDefault = restPose.GetValueOrDefault();
					restPose = game[num2];
					if (restPose.HasValue)
					{
						RestPose valueOrDefault2 = restPose.GetValueOrDefault();
						restPose = game[num3];
						if (restPose.HasValue)
						{
							RestPose valueOrDefault3 = restPose.GetValueOrDefault();
							float num4 = (model[num2].Position - model[num].Position).Length() + (model[num3].Position - model[num2].Position).Length();
							float num5 = (valueOrDefault2.Position - valueOrDefault.Position).Length() + (valueOrDefault3.Position - valueOrDefault2.Position).Length();
							if (!(num4 > 0.0001f))
							{
								return fallback;
							}
							return num5 / num4;
						}
					}
				}
			}
			return fallback;
		}

		internal static float LocalScale(float scale, float bodyScale, float modelRestScale, float gameBoneScale)
		{
			return scale * bodyScale * modelRestScale / ((Math.Abs(gameBoneScale) > 1E-06f) ? gameBoneScale : 1f);
		}

		internal static int IndexOf(IReadOnlyList<WearBone> bones, BodyBone body)
		{
			for (int i = 0; i < bones.Count; i++)
			{
				if (bones[i].Body == body)
				{
					return i;
				}
			}
			return -1;
		}
	}
	internal static class PoseSolver
	{
		internal static string? Validate(IReadOnlyList<PoseLink> links)
		{
			if (links == null || links.Count == 0)
			{
				return "no links";
			}
			for (int i = 0; i < links.Count; i++)
			{
				PoseLink poseLink = links[i];
				if (string.IsNullOrEmpty(poseLink.Model))
				{
					return "link " + i + " names no model bone";
				}
				if (poseLink.Toward >= 0 && poseLink.From >= 0)
				{
					return "link " + i + " (" + poseLink.Model + ") has both a toward and a from";
				}
				if (poseLink.Toward == i || poseLink.From == i)
				{
					return "link " + i + " (" + poseLink.Model + ") points at itself";
				}
				if (poseLink.Toward >= links.Count || poseLink.From >= links.Count || poseLink.Toward < -1 || poseLink.From < -1)
				{
					return "link " + i + " (" + poseLink.Model + ") points outside the " + links.Count + " links";
				}
				for (int j = 0; j < i; j++)
				{
					if (links[j].Model == poseLink.Model)
					{
						return "model bone " + poseLink.Model + " is listed twice";
					}
				}
			}
			return null;
		}

		internal static Quaternion[] Unframe(IReadOnlyList<PoseLink> links, Vector3[] position, Quaternion[] rotation)
		{
			Quaternion[] array = new Quaternion[links.Count];
			for (int i = 0; i < links.Count; i++)
			{
				PoseLink poseLink = links[i];
				Vector3 along = ((poseLink.Toward >= 0) ? (position[poseLink.Toward] - position[i]) : ((poseLink.From >= 0) ? (position[i] - position[poseLink.From]) : Vector3.Zero));
				array[i] = Quaternion.Inverse(BodyMath.BoneFrame(along)) * rotation[i];
			}
			return array;
		}

		internal static Quaternion[] Correct(IReadOnlyList<PoseLink> links, Vector3[] position, Quaternion[] rotation, Vector3?[] toward, Quaternion[] unframe)
		{
			Quaternion[] array = new Quaternion[links.Count];
			for (int i = 0; i < links.Count; i++)
			{
				PoseLink poseLink = links[i];
				Vector3 along = Vector3.Zero;
				if (poseLink.Toward >= 0)
				{
					along = (toward[i] ?? position[poseLink.Toward]) - position[i];
				}
				else if (poseLink.From >= 0)
				{
					along = position[i] - position[poseLink.From];
				}
				array[i] = Quaternion.Inverse(rotation[i]) * BodyMath.BoneFrame(along) * unframe[i];
			}
			return array;
		}

		internal static string? Ratio(float modelRootHeight, float bodyRootHeight, out float ratio)
		{
			ratio = 1f;
			if (bodyRootHeight < 0.1f || modelRootHeight < 0.1f)
			{
				return "the root (hips) stands at " + bodyRootHeight.ToString("0.###") + " m on the body and " + modelRootHeight.ToString("0.###") + " m on the model";
			}
			ratio = modelRootHeight / bodyRootHeight;
			return null;
		}

		internal static string? ValidateReach(IReadOnlyList<PoseReach> reaches, int count)
		{
			for (int i = 0; i < reaches.Count; i++)
			{
				PoseReach poseReach = reaches[i];
				if (poseReach.Upper < 0 || poseReach.Lower < 0 || poseReach.End < 0 || poseReach.Anchor < 0 || poseReach.Upper >= count || poseReach.Lower >= count || poseReach.End >= count || poseReach.Anchor >= count)
				{
					return "reach " + i + " points outside the " + count + " links";
				}
				if (poseReach.Upper == poseReach.Lower || poseReach.Lower == poseReach.End || poseReach.Upper == poseReach.End)
				{
					return "reach " + i + " needs three different links";
				}
			}
			return null;
		}

		internal static Vector3 Elbow(Vector3 root, Vector3 target, float upper, float lower, Vector3 bend, out Vector3 end)
		{
			Vector3 vector = target - root;
			float num = vector.Length();
			Vector3 vector2 = ((num > 1E-05f) ? (vector / num) : Vector3.UnitY);
			float num2 = Math.Clamp(num, Math.Abs(upper - lower) + 0.0001f, upper + lower - 0.0001f);
			end = root + vector2 * num2;
			Vector3 value = bend - vector2 * Vector3.Dot(bend, vector2);
			if (value.LengthSquared() < 1E-10f)
			{
				value = Vector3.Cross(vector2, (Math.Abs(vector2.Y) < 0.99f) ? Vector3.UnitY : Vector3.UnitX);
			}
			float num3 = (upper * upper + num2 * num2 - lower * lower) / (2f * num2);
			float num4 = MathF.Sqrt(Math.Max(0f, upper * upper - num3 * num3));
			return root + vector2 * num3 + Vector3.Normalize(value) * num4;
		}

		internal static Vector3 Root(Vector3 modelRootRest, Vector3 bodyRoot, Vector3 bodyRootRest, float ratio)
		{
			return modelRootRest + (bodyRoot - bodyRootRest) * ratio;
		}
	}
	internal static class HeldPlacement
	{
		internal static Vector3 Position(Quaternion turn, Vector3 source, Vector3 bodyHand, Vector3 modelHand, float scale)
		{
			return modelHand + BodyMath.Rotate(turn, source - bodyHand) * scale;
		}
	}
	internal static class MeshCut
	{
		internal static bool[] KeepVertices(Weights4[] weights, bool[] kept)
		{
			bool[] array = new bool[weights.Length];
			for (int i = 0; i < weights.Length; i++)
			{
				Weights4 weights2 = weights[i];
				float num = K(weights2.I0, weights2.W0);
				float num2 = K(weights2.I1, weights2.W1);
				float num3 = K(weights2.I2, weights2.W2);
				float num4 = K(weights2.I3, weights2.W3);
				float num5 = num + num2 + num3 + num4;
				if (!(num5 < 0.5f))
				{
					array[i] = true;
					weights2.W0 = num / num5;
					weights2.W1 = num2 / num5;
					weights2.W2 = num3 / num5;
					weights2.W3 = num4 / num5;
					weights[i] = weights2;
				}
			}
			return array;
			float K(int index, float weight)
			{
				if (index < 0 || index >= kept.Length || !kept[index])
				{
					return 0f;
				}
				return weight;
			}
		}

		internal static int[] KeepTriangles(int[] triangles, bool[] keep)
		{
			List<int> list = new List<int>(triangles.Length / 4);
			for (int i = 0; i + 2 < triangles.Length; i += 3)
			{
				int num = triangles[i];
				int num2 = triangles[i + 1];
				int num3 = triangles[i + 2];
				if (keep[num] && keep[num2] && keep[num3])
				{
					list.Add(num);
					list.Add(num2);
					list.Add(num3);
				}
			}
			return list.ToArray();
		}
	}
	internal static class Overdraw
	{
		internal const float ScreenBudget = 5f;

		internal const float MaxShed = 0.85f;

		private const float MinDistance = 0.3f;

		private const float Aspect = 1.7777778f;

		private const float FadeBand = 0.15f;

		internal static float Coverage(float size, float distance, float tanHalfFov)
		{
			float num = 2f * Math.Max(distance, 0.3f) * Math.Max(tanHalfFov, 0.01f);
			float num2 = size * size / (num * num * 1.7777778f);
			if (!(num2 > 1f))
			{
				return num2;
			}
			return 1f;
		}

		internal static float Shed(float total, float sheddable, float budget)
		{
			if (total <= budget || sheddable <= 0f)
			{
				return 0f;
			}
			return Math.Min(0.85f, (total - budget) / sheddable);
		}

		internal static float Fade(float cut, float shed)
		{
			if (shed <= 0f)
			{
				return 1f;
			}
			float num = (cut - shed) / 0.15f;
			if (!(num <= 0f))
			{
				if (!(num >= 1f))
				{
					return num;
				}
				return 1f;
			}
			return 0f;
		}
	}
	internal sealed class FxRandom
	{
		private uint _state;

		internal FxRandom(uint seed)
		{
			_state = ((seed == 0) ? 2654435769u : seed);
		}

		internal float Next()
		{
			_state ^= _state << 13;
			_state ^= _state >> 17;
			_state ^= _state << 5;
			return (float)(_state >> 8) * 5.9604645E-08f;
		}

		internal float Range(float low, float high)
		{
			return low + (high - low) * Next();
		}
	}
	internal struct RateDebt
	{
		private float _debt;

		internal int Take(float perSecond, float seconds)
		{
			if (perSecond <= 0f || seconds <= 0f)
			{
				return 0;
			}
			_debt += perSecond * seconds;
			int num = (int)_debt;
			_debt -= num;
			return num;
		}

		internal void Reset()
		{
			_debt = 0f;
		}
	}
	internal static class ForgeCatalog
	{
		internal const string SoftDot = "soft-dot";

		internal const string SoftLine = "soft-line";

		internal static readonly (string Item, string Summary)[] Sprites = new(string, string)[2]
		{
			("soft-dot", "A round soft-edged dot: glows, sparks, smoke puffs and light spots; tinted and sized per use."),
			("soft-line", "A soft-edged streak across its length: tracers, beams and trails; tinted and sized per use.")
		};
	}
	internal readonly record struct ForgeEffectSpec(string Item, bool Line, float DefaultSize, float HoldSeconds, float HoldReach);
	internal static class ForgeEffects
	{
		internal static readonly IReadOnlyList<ForgeEffectSpec> All = new ForgeEffectSpec[11]
		{
			new ForgeEffectSpec("forge_energy_beam", Line: true, float.NaN, 0.12f, 1.5f),
			new ForgeEffectSpec("forge_lightning_arc", Line: true, float.NaN, 0f, 0f),
			new ForgeEffectSpec("forge_blast_tracer", Line: true, float.NaN, 0f, 0f),
			new ForgeEffectSpec("forge_plasma_discharge", Line: true, float.NaN, 0f, 0f),
			new ForgeEffectSpec("forge_plasma_orb", Line: false, 0.3f, 0.25f, 1.5f),
			new ForgeEffectSpec("forge_plasma_explosion", Line: false, 3f, 0f, 0f),
			new ForgeEffectSpec("forge_explosion", Line: false, 2.2f, 0f, 0f),
			new ForgeEffectSpec("forge_flame", Line: false, 8f, 0.12f, 1.5f),
			new ForgeEffectSpec("forge_flame_impact", Line: false, float.NaN, 0f, 0f),
			new ForgeEffectSpec("forge_sparks", Line: false, float.NaN, 0f, 0f),
			new ForgeEffectSpec("forge_black_hole", Line: false, 8f, 0.5f, 2f)
		};
	}
	internal enum GameSource : byte
	{
		PreloadedPool,
		ResourcePrefab,
		MuzzleFlash
	}
	internal sealed record GameEffect(string Item, GameSource Source, string Native, string? AssetPath, bool Line)
	{
		internal string Name => VisualNames.Join("Game", Item);

		[CompilerGenerated]
		private bool PrintMembers(StringBuilder builder)
		{
			RuntimeHelpers.EnsureSufficientExecutionStack();
			builder.Append("Item = ");
			builder.Append((object?)Item);
			builder.Append(", Source = ");
			builder.Append(Source.ToString());
			builder.Append(", Native = ");
			builder.Append((object?)Native);
			builder.Append(", AssetPath = ");
			builder.Append((object?)AssetPath);
			builder.Append(", Line = ");
			builder.Append(Line.ToString());
			return true;
		}
	}
	internal static class GameCatalog
	{
		private const string FxEffects = "Assets/AssetPrefabs/FX_Effects/";

		private const string Muzzle = "Assets/AssetPrefabs/Effects/Weapon/MuzzleFlash/";

		internal static readonly IReadOnlyList<GameEffect> All = new GameEffect[28]
		{
			Pooled("FX_Tripmine", "Assets/AssetPrefabs/FX_Effects/FX_Tripmine.prefab"),
			Pooled("FX_TripmineGlue", "Assets/AssetPrefabs/FX_Effects/FX_TripmineGlue.prefab"),
			Pooled("FX_Tracer", "Assets/AssetPrefabs/FX_Effects/FX_Tracer.prefab")with
			{
				Line = true
			},
			Pooled("FX_BulletImpact_Concrete"),
			Pooled("FX_BulletImpact_Metal"),
			Pooled("FX_BulletImpact_SheetMetal"),
			Pooled("FX_BulletImpact_Glass"),
			Pooled("FX_BulletImpact_Wood"),
			Pooled("FX_BulletImpact_Plastic"),
			Pooled("FX_BulletImpact_Mud"),
			Pooled("FX_BulletImpact_Gravel"),
			Pooled("FX_3D Blood Impact"),
			Pooled("FXC_MeshBloodBomb"),
			Pooled("FX_TorchCutting"),
			Pooled("FX_ElevatorSparks"),
			Pooled("FX_LockMelter"),
			Pooled("FX_InfectionSpit"),
			Resource("fxc_flyerdeath"),
			Resource("fxc_flyerbigdeath"),
			Resource("fx_flyer_teleport"),
			Resource("fx_flyer_big_teleport"),
			Resource("fxc_fleshbulb_pop"),
			Resource("fxc_fleshbulb_pop_boss"),
			Flash("AssaultRifle_MuzzleFlash_3RD"),
			Flash("Pistol_MuzzleFlash_3RD"),
			Flash("Shotgun_MuzzleFlash_3RD"),
			Flash("SubMachine_MuzzleFlash_3RD"),
			Flash("Sentrygun_MuzzleFlash_3RD")
		};

		private static readonly Dictionary<string, GameEffect> ByName = Index();

		internal static bool TryGet(string? name, out GameEffect effect)
		{
			effect = null;
			if (name != null)
			{
				return ByName.TryGetValue(name, out effect);
			}
			return false;
		}

		private static Dictionary<string, GameEffect> Index()
		{
			Dictionary<string, GameEffect> dictionary = new Dictionary<string, GameEffect>(StringComparer.Ordinal);
			foreach (GameEffect item in All)
			{
				string text = VisualNames.CheckItem(item.Item);
				if (text != null)
				{
					throw new InvalidOperationException("Game catalog entry " + item.Native + ": " + text);
				}
				if (!dictionary.TryAdd(item.Name, item))
				{
					throw new InvalidOperationException("Game catalog lists " + item.Name + " twice.");
				}
			}
			return dictionary;
		}

		private static string Item(string native)
		{
			return native.Replace(' ', '_');
		}

		private static GameEffect Pooled(string prefab, string? path = null)
		{
			return new GameEffect(Item(prefab), GameSource.PreloadedPool, prefab, path, Line: false);
		}

		private static GameEffect Resource(string path)
		{
			return new GameEffect(Item(path), GameSource.ResourcePrefab, path, null, Line: false);
		}

		private static GameEffect Flash(string stem)
		{
			return new GameEffect(Item(stem), GameSource.MuzzleFlash, "Assets/AssetPrefabs/Effects/Weapon/MuzzleFlash/" + stem + ".prefab", "Assets/AssetPrefabs/Effects/Weapon/MuzzleFlash/" + stem + ".prefab", Line: false);
		}
	}
	internal static class GunFit
	{
		internal const float MinSpan = 0.05f;

		internal static (float Scale, Vector3 Move)? Solve(Vector3 nativeRight, Vector3 nativeLeft, Vector3? nativeMuzzle, Vector3 modelRight, Vector3 modelLeft, Vector3? modelMuzzle, float minScale, float maxScale, Vector3? nativeSight = null, Vector3? modelSight = null)
		{
			float num3;
			float z;
			float num4;
			if (Finite(nativeRight) && Finite(nativeLeft) && Finite(modelRight) && Finite(modelLeft))
			{
				if (nativeMuzzle.HasValue)
				{
					Vector3 valueOrDefault = nativeMuzzle.GetValueOrDefault();
					if (!Finite(valueOrDefault))
					{
						goto IL_009a;
					}
				}
				if (modelMuzzle.HasValue)
				{
					Vector3 valueOrDefault2 = modelMuzzle.GetValueOrDefault();
					if (!Finite(valueOrDefault2))
					{
						goto IL_009a;
					}
				}
				if (nativeSight.HasValue)
				{
					Vector3 valueOrDefault3 = nativeSight.GetValueOrDefault();
					if (!Finite(valueOrDefault3))
					{
						goto IL_009a;
					}
				}
				if (modelSight.HasValue)
				{
					Vector3 valueOrDefault4 = modelSight.GetValueOrDefault();
					if (!Finite(valueOrDefault4))
					{
						goto IL_009a;
					}
				}
				if (minScale > 0f && maxScale >= minScale)
				{
					float num = nativeLeft.Z - nativeRight.Z;
					float num2 = modelLeft.Z - modelRight.Z;
					num3 = ((num >= 0.05f && num2 >= 0.05f) ? Math.Clamp(num / num2, minScale, maxScale) : 1f);
					z = nativeRight.Z - num3 * modelRight.Z;
					if (nativeSight.HasValue)
					{
						Vector3 valueOrDefault5 = nativeSight.GetValueOrDefault();
						if (modelSight.HasValue)
						{
							Vector3 valueOrDefault6 = modelSight.GetValueOrDefault();
							num4 = valueOrDefault5.Y - num3 * valueOrDefault6.Y;
							goto IL_0161;
						}
					}
					num4 = (nativeRight.Y - num3 * modelRight.Y + (nativeLeft.Y - num3 * modelLeft.Y)) * 0.5f;
					goto IL_0161;
				}
			}
			goto IL_009a;
			IL_0161:
			float y = num4;
			float num5;
			if (nativeMuzzle.HasValue)
			{
				Vector3 valueOrDefault7 = nativeMuzzle.GetValueOrDefault();
				if (modelMuzzle.HasValue)
				{
					Vector3 valueOrDefault8 = modelMuzzle.GetValueOrDefault();
					num5 = valueOrDefault7.X - num3 * valueOrDefault8.X;
					goto IL_01ad;
				}
			}
			num5 = nativeRight.X - num3 * modelRight.X;
			goto IL_01ad;
			IL_009a:
			return null;
			IL_01ad:
			float x = num5;
			return (num3, new Vector3(x, y, z));
		}

		private static bool Finite(Vector3 v)
		{
			if (float.IsFinite(v.X) && float.IsFinite(v.Y))
			{
				return float.IsFinite(v.Z);
			}
			return false;
		}
	}
	internal sealed class ModelProfile
	{
		internal sealed class Surface
		{
			public string key { get; set; } = "";

			public string albedo { get; set; } = "";

			public string metallic { get; set; } = "";

			public string normal { get; set; } = "";

			public string emission { get; set; } = "";

			public float[] emissionColor { get; set; } = Array.Empty<float>();

			internal bool Emissive
			{
				get
				{
					if (emission.Length != 0)
					{
						return emissionColor.Length == 3;
					}
					return false;
				}
			}
		}

		internal sealed class RendererEntry
		{
			public string name { get; set; } = "";

			public string[] surfaces { get; set; } = Array.Empty<string>();
		}

		internal sealed class Prefab
		{
			public string name { get; set; } = "";

			public RendererEntry[] renderers { get; set; } = Array.Empty<RendererEntry>();

			public string[] anchors { get; set; } = Array.Empty<string>();
		}

		private sealed class Document
		{
			public int format { get; set; }

			public Prefab[] prefabs { get; set; } = Array.Empty<Prefab>();

			public Surface[] surfaces { get; set; } = Array.Empty<Surface>();

			public string[] textures { get; set; } = Array.Empty<string>();
		}

		internal const string AssetName = "ordnance-profile";

		internal const int Format = 1;

		internal IReadOnlyList<Prefab> Prefabs { get; }

		internal IReadOnlyList<Surface> Surfaces { get; }

		internal IReadOnlyList<string> Textures { get; }

		private ModelProfile(Document d)
		{
			Prefabs = d.prefabs;
			Surfaces = d.surfaces;
			Textures = d.textures;
		}

		internal static ModelProfile? Read(string json, out string? why)
		{
			why = null;
			Document document;
			try
			{
				document = JsonSerializer.Deserialize<Document>(json);
			}
			catch (JsonException ex)
			{
				why = "the profile is not valid JSON: " + ex.Message;
				return null;
			}
			if (document == null)
			{
				why = "the profile is empty";
				return null;
			}
			if (document.format != 1)
			{
				why = "profile format " + document.format + " is not " + 1 + "; rebuild the bundle";
				return null;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			Surface[] surfaces = document.surfaces;
			foreach (Surface surface in surfaces)
			{
				if (surface == null || surface.key.Length == 0)
				{
					why = "a surface has no key";
					return null;
				}
				if (!hashSet.Add(surface.key))
				{
					why = "surface " + surface.key + " is listed twice";
					return null;
				}
				if (surface.albedo.Length == 0 || surface.metallic.Length == 0)
				{
					why = "surface " + surface.key + " lacks its albedo or metallic map";
					return null;
				}
			}
			HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal);
			Prefab[] prefabs = document.prefabs;
			string[] surfaces2;
			foreach (Prefab prefab in prefabs)
			{
				if (prefab == null || prefab.name.Length == 0)
				{
					why = "a prefab has no name";
					return null;
				}
				string text = VisualNames.CheckItem(prefab.name);
				if (text != null)
				{
					why = text;
					return null;
				}
				if (!hashSet2.Add(prefab.name))
				{
					why = "prefab " + prefab.name + " is listed twice";
					return null;
				}
				RendererEntry[] renderers = prefab.renderers;
				foreach (RendererEntry rendererEntry in renderers)
				{
					surfaces2 = rendererEntry.surfaces;
					foreach (string text2 in surfaces2)
					{
						if (!hashSet.Contains(text2))
						{
							why = "prefab " + prefab.name + " renderer " + rendererEntry.name + " names the unknown surface " + text2;
							return null;
						}
					}
				}
			}
			HashSet<string> hashSet3 = new HashSet<string>(StringComparer.Ordinal);
			surfaces2 = document.textures;
			foreach (string text3 in surfaces2)
			{
				string text4 = VisualNames.CheckItem(text3);
				if (text4 != null)
				{
					why = text4;
					return null;
				}
				if (!hashSet3.Add(text3))
				{
					why = "texture " + text3 + " is listed twice";
					return null;
				}
			}
			return new ModelProfile(document);
		}
	}
	internal static class VisualNames
	{
		internal const string Game = "Game";

		internal const string Forge = "Forge";

		internal static string? CheckPack(string? pack, bool builtIn = false)
		{
			if (string.IsNullOrEmpty(pack))
			{
				return "the pack name is empty";
			}
			foreach (char c in pack)
			{
				if (!IsNameChar(c) || c == '.')
				{
					return "the pack name '" + pack + "' may only hold letters, digits, '_' and '-'";
				}
			}
			if (string.Equals(pack, "Game", StringComparison.OrdinalIgnoreCase))
			{
				return "'Game' is the game's own catalog";
			}
			if (!builtIn && string.Equals(pack, "Forge", StringComparison.OrdinalIgnoreCase))
			{
				return "'Forge' is this library's own namespace";
			}
			return null;
		}

		internal static string? CheckItem(string? item)
		{
			if (string.IsNullOrEmpty(item))
			{
				return "the item name is empty";
			}
			for (int i = 0; i < item.Length; i++)
			{
				if (!IsNameChar(item[i]))
				{
					return "the item name '" + item + "' may only hold letters, digits, '_', '-' and '.'";
				}
			}
			return null;
		}

		internal static string Join(string pack, string item)
		{
			return pack + ":" + item;
		}

		internal static bool TrySplit(string? name, out string pack, out string item, out string? why)
		{
			pack = (item = "");
			why = null;
			if (string.IsNullOrEmpty(name))
			{
				why = "the name is empty";
				return false;
			}
			int num = name.IndexOf(':');
			if (num <= 0 || num == name.Length - 1 || name.IndexOf(':', num + 1) >= 0)
			{
				why = "'" + name + "' is not Pack:item";
				return false;
			}
			pack = name.Substring(0, num);
			item = name.Substring(num + 1);
			why = CheckItem(item);
			string text = pack;
			foreach (char c in text)
			{
				if ((!IsNameChar(c) || c == '.') && why == null)
				{
					why = "the pack name '" + pack + "' may only hold letters, digits, '_' and '-'";
				}
			}
			return why == null;
		}

		private static bool IsNameChar(char c)
		{
			switch (c)
			{
			case '-':
			case '.':
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
			case 'A':
			case 'B':
			case 'C':
			case 'D':
			case 'E':
			case 'F':
			case 'G':
			case 'H':
			case 'I':
			case 'J':
			case 'K':
			case 'L':
			case 'M':
			case 'N':
			case 'O':
			case 'P':
			case 'Q':
			case 'R':
			case 'S':
			case 'T':
			case 'U':
			case 'V':
			case 'W':
			case 'X':
			case 'Y':
			case 'Z':
			case '_':
			case 'a':
			case 'b':
			case 'c':
			case 'd':
			case 'e':
			case 'f':
			case 'g':
			case 'h':
			case 'i':
			case 'j':
			case 'k':
			case 'l':
			case 'm':
			case 'n':
			case 'o':
			case 'p':
			case 'q':
			case 'r':
			case 's':
			case 't':
			case 'u':
			case 'v':
			case 'w':
			case 'x':
			case 'y':
			case 'z':
				return true;
			default:
				return false;
			}
		}
	}
	internal sealed class NameTable<T> where T : class
	{
		private readonly Dictionary<string, T> _byName = new Dictionary<string, T>(StringComparer.Ordinal);

		private readonly List<string> _names = new List<string>();

		internal int Count => _byName.Count;

		internal IReadOnlyList<string> Names => _names;

		internal string? Add(string name, T value)
		{
			if (!VisualNames.TrySplit(name, out string _, out string _, out string why))
			{
				return why;
			}
			if (_byName.ContainsKey(name))
			{
				return "'" + name + "' is already registered";
			}
			_byName.Add(name, value);
			_names.Add(name);
			return null;
		}

		internal bool TryGet(string? name, out T value)
		{
			value = null;
			if (name != null)
			{
				return _byName.TryGetValue(name, out value);
			}
			return false;
		}

		internal bool Remove(string name)
		{
			if (!_byName.Remove(name))
			{
				return false;
			}
			_names.Remove(name);
			return true;
		}
	}
	internal static class Missing
	{
		internal static string Why(string? name, Func<string, bool> packKnown, string kind)
		{
			if (!VisualNames.TrySplit(name, out string pack, out string _, out string why))
			{
				return why;
			}
			if (!packKnown(pack))
			{
				return "no pack " + pack + " is registered (is the mod that owns it installed?)";
			}
			return "pack " + pack + " has no " + kind + " '" + name + "'";
		}
	}
	public readonly struct OutlineColor : IEquatable<OutlineColor>
	{
		public float R { get; }

		public float G { get; }

		public float B { get; }

		public float A { get; }

		internal bool Valid
		{
			get
			{
				if (float.IsFinite(R) && float.IsFinite(G) && float.IsFinite(B) && R >= 0f && G >= 0f && B >= 0f)
				{
					float a = A;
					if (a >= 0f)
					{
						return a <= 1f;
					}
					return false;
				}
				return false;
			}
		}

		public OutlineColor(float r, float g, float b, float a = 1f)
		{
			R = r;
			G = g;
			B = b;
			A = a;
		}

		public bool Equals(OutlineColor other)
		{
			if (R == other.R && G == other.G && B == other.B)
			{
				return A == other.A;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is OutlineColor other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(R, G, B, A);
		}
	}
	public sealed class EnemyOutlineStyle
	{
		public const int MaxEnemiesLimit = 128;

		public const float RangeLimit = 500f;

		public const float WidthLimit = 16f;

		public float Range { get; init; } = 35f;

		public float FadeDistance { get; init; } = 5f;

		public int MaxEnemies { get; init; } = 24;

		public float Width { get; init; } = 1.6f;

		public OutlineColor Sleeping { get; init; } = new OutlineColor(0.23f, 0.4f, 0.44f, 0.4f);

		public OutlineColor Awake { get; init; } = new OutlineColor(0.8f, 0.56f, 0.22f, 0.65f);

		public OutlineColor Hunting { get; init; } = new OutlineColor(0.8f, 0.18f, 0.18f, 0.8f);

		public bool XRay { get; init; }

		public int Priority { get; init; }

		public OutlineColor ColorOf(EnemyAlert state)
		{
			//IL_0000: 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_0014: Expected I4, but got Unknown
			return (state - 1) switch
			{
				0 => Sleeping, 
				1 => Awake, 
				2 => Hunting, 
				_ => default(OutlineColor), 
			};
		}

		public string? Problem()
		{
			if (!float.IsFinite(Range) || Range <= 0f || Range > 500f)
			{
				return "Range must be above 0 and at most " + 500f + " metres";
			}
			if (!float.IsFinite(FadeDistance) || FadeDistance < 0f || FadeDistance > Range)
			{
				return "FadeDistance must be between 0 and Range";
			}
			if (MaxEnemies < 1 || MaxEnemies > 128)
			{
				return "MaxEnemies must be between 1 and " + 128;
			}
			if (!float.IsFinite(Width) || Width <= 0f || Width > 16f)
			{
				return "Width must be above 0 and at most " + 16f + " pixels";
			}
			if (!Sleeping.Valid || !Awake.Valid || !Hunting.Valid)
			{
				return "colours must be finite, not negative, with alpha 0..1";
			}
			return null;
		}
	}
	public static class OutlineRules
	{
		public const float DefaultWidth = 1.6f;

		public const float NearAlways = 3f;

		public const float ViewCosine = -0.1f;

		public const int RefreshPerFrame = 24;

		public const int LimbSettleFrames = 45;

		public const float WakeSeconds = 6f;

		public const float WakeScanSeconds = 0.25f;

		public const float Unlimited = 1000000f;

		public static float PixelWidth(float width1080, int screenHeight)
		{
			return width1080 * (float)Math.Max(1, screenHeight) / 1080f;
		}

		public static bool WakeScanDue(float now, float wakeUntil, float nextScan)
		{
			if (now < wakeUntil)
			{
				return now >= nextScan;
			}
			return false;
		}

		public static float Until(float now, float seconds)
		{
			if (!(seconds > 0f))
			{
				return float.PositiveInfinity;
			}
			return now + seconds;
		}

		public static string? Problem(OutlineColor color, float seconds)
		{
			if (!color.Valid)
			{
				return "the colour must be finite, not negative, with alpha 0..1";
			}
			if (!float.IsFinite(seconds) || seconds < 0f)
			{
				return "seconds must be 0 (until removed) or more";
			}
			return null;
		}
	}
	public static class OutlineCuts
	{
		public const int Max = 4;

		public static bool Removes(ReadOnlySpan<float> matrices, ReadOnlySpan<float> inverts, int count, float x, float y, float z)
		{
			float num = 0f;
			for (int i = 0; i < Math.Min(count, 4); i++)
			{
				ReadOnlySpan<float> readOnlySpan = matrices.Slice(16 * i, 16);
				float num2 = readOnlySpan[0] * x + readOnlySpan[1] * y + readOnlySpan[2] * z + readOnlySpan[3];
				float num3 = readOnlySpan[4] * x + readOnlySpan[5] * y + readOnlySpan[6] * z + readOnlySpan[7];
				float num4 = readOnlySpan[8] * x + readOnlySpan[9] * y + readOnlySpan[10] * z + readOnlySpan[11];
				float num5 = Math.Min(MathF.Sqrt(num2 * num2 + num3 * num3 + num4 * num4), 1f);
				num = Math.Max(num, (inverts[i] != 0f) ? num5 : (1f - num5));
			}
			return num > 0.5f;
		}
	}
	public static class OutlineDrawSet
	{
		public static int Collect<T>(IEnumerable<T> candidates, Func<T, bool> drawn, int max, List<T> into)
		{
			into.Clear();
			int num = 0;
			foreach (T candidate in candidates)
			{
				if (!drawn(candidate))
				{
					num++;
				}
				else if (into.Count < max)
				{
					into.Add(candidate);
				}
			}
			return num;
		}
	}
	public sealed class OutlineClaims
	{
		private long[] _key = new long[16];

		private long[] _stamp = new long[16];

		private int[] _priority = new int[16];

		private int[] _generation = new int[16];

		private float[] _until = new float[16];

		private bool[] _used = new bool[16];

		private int _high;

		private int _live;

		private long _clock;

		public int Capacity => _high;

		public int Count => _live;

		public bool Live(int slot)
		{
			if (slot >= 0 && slot < _high)
			{
				return _used[slot];
			}
			return false;
		}

		public long Key(int slot)
		{
			return _key[slot];
		}

		public int Priority(int slot)
		{
			return _priority[slot];
		}

		public int Generation(int slot)
		{
			if (slot < 0 || slot >= _high)
			{
				return 0;
			}
			return _generation[slot];
		}

		public int Add(long key, int priority, float until)
		{
			int num = -1;
			for (int i = 0; i < _high; i++)
			{
				if (!_used[i])
				{
					num = i;
					break;
				}
			}
			if (num < 0)
			{
				if (_high == _used.Length)
				{
					Grow();
				}
				num = _high++;
			}
			_used[num] = true;
			_key[num] = key;
			_priority[num] = priority;
			_until[num] = until;
			_stamp[num] = ++_clock;
			_live++;
			return num;
		}

		public bool Remove(int slot, int generation)
		{
			if (!Live(slot) || _generation[slot] != generation)
			{
				return false;
			}
			Free(slot);
			return true;
		}

		public bool Expire(float now)
		{
			bool result = false;
			for (int i = 0; i < _high; i++)
			{
				if (_used[i] && now >= _until[i])
				{
					Free(i);
					result = true;
				}
			}
			return result;
		}

		public int Winner(long key)
		{
			int num = -1;
			for (int i = 0; i < _high; i++)
			{
				if (_used[i] && _key[i] == key && (num < 0 || _priority[i] > _priority[num] || (_priority[i] == _priority[num] && _stamp[i] > _stamp[num])))
				{
					num = i;
				}
			}
			return num;
		}

		public bool Overrides(long key, int priority)
		{
			int num = Winner(key);
			if (num >= 0)
			{
				return _priority[num] >= priority;
			}
			return false;
		}

		public void Clear()
		{
			for (int i = 0; i < _high; i++)
			{
				if (_used[i])
				{
					Free(i);
				}
			}
		}

		private void Free(int slot)
		{
			_used[slot] = false;
			_generation[slot]++;
			_live--;
		}

		private void Grow()
		{
			int newSize = _used.Length * 2;
			Array.Resize(ref _key, newSize);
			Array.Resize(ref _stamp, newSize);
			Array.Resize(ref _priority, newSize);
			Array.Resize(ref _generation, newSize);
			Array.Resize(ref _until, newSize);
			Array.Resize(ref _used, newSize);
		}
	}
	public sealed class EnemyOutlineTracker
	{
		private bool[] _used = new bool[64];

		private int[] _generation = new int[64];

		private float[] _x = new float[64];

		private float[] _y = new float[64];

		private float[] _z = new float[64];

		private EnemyAlert[] _state = (EnemyAlert[])(object)new EnemyAlert[64];

		private int _high;

		private int _cursor;

		private int[] _selSlot = new int[128];

		private int[] _selGen = new int[128];

		private EnemyAlert[] _selState = (EnemyAlert[])(object)new EnemyAlert[128];

		private readonly int[] _newSlot = new int[128];

		private readonly float[] _newDist = new float[128];

		private int[] _nextSlot = new int[128];

		private int[] _nextGen = new int[128];

		private EnemyAlert[] _nextState = (EnemyAlert[])(object)new EnemyAlert[128];

		public int Capacity => _high;

		public int SelectedCount { get; private set; }

		public bool Used(int slot)
		{
			if (slot >= 0 && slot < _high)
			{
				return _used[slot];
			}
			return false;
		}

		public int Generation(int slot)
		{
			if (!Used(slot))
			{
				return 0;
			}
			return _generation[slot];
		}

		public EnemyAlert State(int slot)
		{
			if (Used(slot))
			{
				return _state[slot];
			}
			return (EnemyAlert)0;
		}

		public int NextSlot(int slotCount)
		{
			if (slotCount <= 0)
			{
				return -1;
			}
			if (_cursor >= slotCount)
			{
				_cursor = 0;
			}
			return _cursor++;
		}

		public void Set(int slot, int generation, float x, float y, float z, EnemyAlert state)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected I4, but got Unknown
			if (slot >= 0)
			{
				if (slot >= _used.Length)
				{
					Grow(slot + 1);
				}
				if (slot >= _high)
				{
					_high = slot + 1;
				}
				_used[slot] = true;
				_generation[slot] = generation;
				_x[slot] = x;
				_y[slot] = y;
				_z[slot] = z;
				_state[slot] = (EnemyAlert)(int)state;
			}
		}

		public bool Release(int slot)
		{
			if (!Used(slot))
			{
				return false;
			}
			_used[slot] = false;
			_state[slot] = (EnemyAlert)0;
			return IsSelected(slot);
		}

		public bool IsSelected(int slot)
		{
			for (int i = 0; i < SelectedCount; i++)
			{
				if (_selSlot[i] == slot)
				{
					return true;
				}
			}
			return false;
		}

		public int SelectedSlot(int index)
		{
			return _selSlot[index];
		}

		public EnemyAlert SelectedState(int index)
		{
			return _selState[index];
		}

		public void ClearSelection()
		{
			SelectedCount = 0;
		}

		public bool Select(EnemyOutlineStyle style, float cx, float cy, float cz, float fx, float fy, float fz)
		{
			int num = Math.Clamp(style.MaxEnemies, 1, 128);
			float num2 = style.Range * style.Range;
			float num3 = 9f;
			int num4 = 0;
			for (int i = 0; i < _high; i++)
			{
				if (!_used[i] || (int)_state[i] == 0)
				{
					continue;
				}
				float num5 = _x[i] - cx;
				float num6 = _y[i] - cy;
				float num7 = _z[i] - cz;
				float num8 = num5 * num5 + num6 * num6 + num7 * num7;
				if (!(num8 > num2) && (!(num8 > num3) || !(num5 * fx + num6 * fy + num7 * fz < -0.1f * MathF.Sqrt(num8))) && (num4 != num || !(num8 >= _newDist[num4 - 1])))
				{
					int num9 = ((num4 < num) ? num4++ : (num4 - 1));
					while (num9 > 0 && _newDist[num9 - 1] > num8)
					{
						_newDist[num9] = _newDist[num9 - 1];
						_newSlot[num9] = _newSlot[num9 - 1];
						num9--;
					}
					_newDist[num9] = num8;
					_newSlot[num9] = i;
				}
			}
			for (int j = 0; j < num4; j++)
			{
				int num10 = _newSlot[j];
				int num11 = j;
				while (num11 > 0 && _nextSlot[num11 - 1] > num10)
				{
					_nextSlot[num11] = _nextSlot[num11 - 1];
					num11--;
				}
				_nextSlot[num11] = num10;
			}
			bool flag = num4 != SelectedCount;
			for (int k = 0; k < num4; k++)
			{
				int num12 = _nextSlot[k];
				_nextGen[k] = _generation[num12];
				_nextState[k] = _state[num12];
				if (!flag && (_selSlot[k] != num12 || _selGen[k] != _nextGen[k] || (int)_selState[k] != (int)_nextState[k]))
				{
					flag = true;
				}
			}
			if (!flag)
			{
				return false;
			}
			int[] nextSlot = _nextSlot;
			int[] selSlot = _selSlot;
			_selSlot = nextSlot;
			_nextSlot = selSlot;
			selSlot = _nextGen;
			nextSlot = _selGen;
			_selGen = selSlot;
			_nextGen = nextSlot;
			EnemyAlert[] nextState = _nextState;
			EnemyAlert[] selState = _selState;
			_selState = nextState;
			_nextState = selState;
			SelectedCount = num4;
			return true;
		}

		private void Grow(int needed)
		{
			int num;
			for (num = _used.Length; num < needed; num *= 2)
			{
			}
			Array.Resize(ref _used, num);
			Array.Resize(ref _generation, num);
			Array.Resize(ref _x, num);
			Array.Resize(ref _y, num);
			Array.Resize(ref _z, num);
			Array.Resize(ref _state, num);
		}
	}
	public sealed class OutlineScopes<T> where T : class
	{
		private readonly List<(T Scope, long Stamp)> _on = new List<(T, long)>();

		private long _clock;

		public T? Current { get; private set; }

		public bool Set(T scope, bool on)
		{
			int num = -1;
			for (int i = 0; i < _on.Count; i++)
			{
				if (_on[i].Scope == scope)
				{
					num = i;
					break;
				}
			}
			if (on && num < 0)
			{
				_on.Add((scope, ++_clock));
			}
			else
			{
				if (on || num < 0)
				{
					return false;
				}
				_on.RemoveAt(num);
			}
			T current = Current;
			Current = null;
			long num2 = long.MinValue;
			foreach (var (current2, num3) in _on)
			{
				if (num3 > num2)
				{
					num2 = num3;
					Current = current2;
				}
			}
			return current != Current;
		}

		public bool IsOn(T scope)
		{
			foreach (var item in _on)
			{
				if (item.Scope == scope)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ParticleBudget
	{
		internal static bool Admits(int live, int capacity, int priority)
		{
			if (capacity > 0 && live >= capacity)
			{
				return priority > 0;
			}
			return true;
		}
	}
	internal sealed class PooledBodies<T> where T : class
	{
		private readonly List<T> _live = new List<T>();

		private readonly Stack<T> _free = new Stack<T>();

		internal int LiveCount => _live.Count;

		internal int FreeCount => _free.Count;

		internal T this[int index] => _live[index];

		internal T? Reuse(Func<T, bool> usable)
		{
			while (_free.Count > 0)
			{
				T val = _free.Pop();
				if (usable(val))
				{
					return val;
				}
			}
			return null;
		}

		internal void Add(T item)
		{
			_live.Add(item);
		}

		internal void RemoveAt(int index)
		{
			_live.RemoveAt(index);
		}

		internal bool Release(T item, Action<T> hide, bool usable)
		{
			if (!_live.Contains(item))
			{
				return false;
			}
			hide(item);
			_live.Remove(item);
			if (usable)
			{
				_free.Push(item);
			}
			return true;
		}
	}
	internal static class ShakeMath
	{
		internal static float Setting(float configured)
		{
			if (!float.IsNaN(configured))
			{
				if (!(configured < 0f))
				{
					if (!(configured > 1f))
					{
						return configured;
					}
					return 1f;
				}
				return 0f;
			}
			return 1f;
		}

		internal static float Falloff(float distance, float inner, float range)
		{
			if (!(range > 0f) || !(distance < range))
			{
				return 0f;
			}
			if (distance <= inner)
			{
				return 1f;
			}
			return 1f - (distance - inner) / (range - inner);
		}
	}
	internal sealed class ShakeStack
	{
		private readonly float[] _start;

		private readonly float[] _seconds;

		private readonly float[] _amplitude;

		internal ShakeStack(int capacity)
		{
			if (capacity <= 0)
			{
				throw new ArgumentOutOfRangeException("capacity", "A stack holds at least one shake.");
			}
			_start = new float[capacity];
			_seconds = new float[capacity];
			_amplitude = new float[capacity];
		}

		internal float Live(float now)
		{
			float num = 0f;
			for (int i = 0; i < _amplitude.Length; i++)
			{
				num += Share(i, now);
			}
			return num;
		}

		internal float Admit(float now, float amplitude, float seconds, float cap)
		{
			if (!(amplitude > 0f) || !(seconds > 0f) || !(cap > 0f))
			{
				return 0f;
			}
			float num = cap - Live(now);
			if (num <= 0f)
			{
				return 0f;
			}
			float num2 = Math.Min(amplitude, num);
			int num3 = 0;
			float num4 = float.MaxValue;
			for (int i = 0; i < _amplitude.Length; i++)
			{
				float num5 = Share(i, now);
				if (num5 < num4)
				{
					num4 = num5;
					num3 = i;
				}
			}
			_start[num3] = now;
			_seconds[num3] = seconds;
			_amplitude[num3] = num2;
			return num2;
		}

		internal void Clear()
		{
			Array.Clear(_amplitude, 0, _amplitude.Length);
		}

		private float Share(int i, float now)
		{
			if (_amplitude[i] <= 0f)
			{
				return 0f;
			}
			float num = now - _start[i];
			if (num < 0f)
			{
				num = 0f;
			}
			if (!(num >= _seconds[i]))
			{
				return _amplitude[i] * (1f - num / _seconds[i]);
			}
			return 0f;
		}
	}
	internal sealed class SlotBook
	{
		private readonly bool[] _live;

		private readonly bool[] _pinned;

		private readonly int[] _priority;

		private readonly int[] _generation;

		private readonly long[] _started;

		private long _sequence;

		private int _scan;

		internal int Capacity => _live.Length;

		internal int LiveCount { get; private set; }

		internal SlotBook(int capacity)
		{
			if (capacity <= 0)
			{
				throw new ArgumentOutOfRangeException("capacity", "A pool holds at least one item.");
			}
			_live = new bool[capacity];
			_pinned = new bool[capacity];
			_priority = new int[capacity];
			_generation = new int[capacity];
			_started = new long[capacity];
		}

		internal bool Live(int slot)
		{
			return _live[slot];
		}

		internal int Generation(int slot)
		{
			return _generation[slot];
		}

		internal int Take(int priority, bool pinned, out bool replaced)
		{
			replaced = false;
			int num = _live.Length;
			for (int i = 0; i < num; i++)
			{
				int num2 = (_scan + i) % num;
				if (!_live[num2])
				{
					_scan = (num2 + 1) % num;
					Start(num2, priority, pinned);
					LiveCount++;
					return num2;
				}
			}
			int num3 = -1;
			for (int j = 0; j < num; j++)
			{
				if (!_pinned[j] && _priority[j] < priority && (num3 < 0 || _priority[j] < _priority[num3] || (_priority[j] == _priority[num3] && _started[j] < _started[num3])))
				{
					num3 = j;
				}
			}
			if (num3 < 0)
			{
				return -1;
			}
			replaced = true;
			Start(num3, priority, pinned);
			return num3;
		}

		internal void Free(int slot)
		{
			if (_live[slot])
			{
				_live[slot] = false;
				_pinned[slot] = false;
				_generation[slot]++;
				LiveCount--;
			}
		}

		internal void Unpin(int slot)
		{
			_pinned[slot] = false;
		}

		internal void Clear()
		{
			for (int i = 0; i < _live.Length; i++)
			{
				Free(i);
			}
		}

		private void Start(int slot, int priority, bool pinned)
		{
			_live[slot] = true;
			_pinned[slot] = pinned;
			_priority[slot] = priority;
			_generation[slot]++;
			_started[slot] = ++_sequence;
		}
	}
	internal sealed class DecalSlots
	{
		private readonly bool[] _live;

		private readonly int[] _generation;

		private readonly long[] _started;

		private long _sequence;

		internal int Capacity => _live.Length;

		internal int LiveCount { get; private set; }

		internal DecalSlots(int capacity)
		{
			if (capacity <= 0)
			{
				throw new ArgumentOutOfRangeException("capacity", "A set of marks holds at least one.");
			}
			_live = new bool[capacity];
			_generation = new int[capacity];
			_started = new long[capacity];
		}

		internal bool Live(int slot)
		{
			return _live[slot];
		}

		internal int Generation(int slot)
		{
			return _generation[slot];
		}

		internal int Take()
		{
			int num = -1;
			for (int i = 0; i < _live.Length; i++)
			{
				if (!_live[i])
				{
					num = i;
					break;
				}
				if (num < 0 || _started[i] < _started[num])
				{
					num = i;
				}
			}
			if (!_live[num])
			{
				LiveCount++;
			}
			_live[num] = true;
			_generation[num]++;
			_started[num] = ++_sequence;
			return num;
		}

		internal bool Current(int slot, int generation)
		{
			if (slot >= 0 && slot < _live.Length && _live[slot])
			{
				return _generation[slot] == generation;
			}
			return false;
		}

		internal void End(int slot)
		{
			if (_live[slot])
			{
				_live[slot] = false;
				_generation[slot]++;
				LiveCount--;
			}
		}

		internal void Clear()
		{
			for (int i = 0; i < _live.Length; i++)
			{
				End(i);
			}
		}
	}
	internal static class DecalMath
	{
		internal static float Hold(float life, float fade)
		{
			if (!(life > 0f))
			{
				return 0f;
			}
			if (!(fade > 0f))
			{
				return 1f;
			}
			float num = 1f - fade / life;
			if (!(num < 0f))
			{
				return num;
			}
			return 0f;
		}
	}
	internal static class LightSlots
	{
		internal static int Pick(bool[] used, bool[] held, float[] ends, float now)
		{
			for (int i = 0; i < used.Length; i++)
			{
				if (!used[i])
				{
					return i;
				}
			}
			int result = -1;
			float num = float.MaxValue;
			for (int j = 0; j < used.Length; j++)
			{
				if (!held[j])
				{
					float num2 = ends[j] - now;
					if (num2 < num)
					{
						num = num2;
						result = j;
					}
				}
			}
			return result;
		}

		internal static float Blink(float age, float rate)
		{
			if (!(rate > 0f))
			{
				return 1f;
			}
			float num = age * rate;
			if (!(num - (float)Math.Floor(num) < 0.5f))
			{
				return 0f;
			}
			return 1f;
		}
	}
	internal sealed class HoldBook
	{
		private readonly bool[] _playing;

		private readonly bool[] _emitting;

		private readonly float[] _until;

		private readonly float[] _x;

		private readonly float[] _y;

		private readonly float[] _z;

		private readonly long[] _started;

		private long _sequence;

		internal int Copies => _playing.Length;

		internal HoldBook(int copies)
		{
			if (copies <= 0)
			{
				throw new ArgumentOutOfRangeException("copies", "An effect keeps at least one copy.");
			}
			_playing = new bool[copies];
			_emitting = new bool[copies];
			_until = new float[copies];
			_x = new float[copies];
			_y = new float[copies];
			_z = new float[copies];
			_started = new long[copies];
		}

		internal bool Playing(int copy)
		{
			return _playing[copy];
		}

		internal bool Emitting(int copy)
		{
			return _emitting[copy];
		}

		internal int Near(float x, float y, float z, float reach)
		{
			int result = -1;
			float num = reach * reach;
			for (int i = 0; i < _playing.Length; i++)
			{
				if (_playing[i] && _emitting[i])
				{
					float num2 = _x[i] - x;
					float num3 = _y[i] - y;
					float num4 = _z[i] - z;
					float num5 = num2 * num2 + num3 * num3 + num4 * num4;
					if (num5 <= num)
					{
						num = num5;
						result = i;
					}
				}
			}
			return result;
		}

		internal int Take()
		{
			int num = 0;
			for (int i = 0; i < _playing.Length; i++)
			{
				if (!_playing[i])
				{
					return i;
				}
				if (_started[i] < _started[num])
				{
					num = i;
				}
			}
			return num;
		}

		internal void Start(int copy, float x, float y, float z, float now, float window)
		{
			_playing[copy] = true;
			_emitting[copy] = window > 0f;
			_until[copy] = ((window > 0f) ? (now + window) : 0f);
			_started[copy] = ++_sequence;
			Place(copy, x, y, z);
		}

		internal void Extend(int copy, float x, float y, float z, float now, float window)
		{
			_until[copy] = now + window;
			Place(copy, x, y, z);
		}

		internal bool Expired(int copy, float now)
		{
			if (!_playing[copy] || !_emitting[copy] || now < _until[copy])
			{
				return false;
			}
			_emitting[copy] = false;
			return true;
		}

		internal void Stop(int copy)
		{
			_emitting[copy] = false;
		}

		internal void Finished(int copy)
		{
			_playing[copy] = false;
			_emitting[copy] = false;
		}

		private void Place(int copy, float x, float y, float z)
		{
			_x[copy] = x;
			_y[copy] = y;
			_z[copy] = z;
		}
	}
	internal sealed class RibbonRing<T> where T : struct
	{
		private readonly T[] _ring;

		private int _head;

		private float _next;

		internal int Count => _ring.Length;

		internal float Step { get; }

		internal T this[int i] => _ring[(_head - i + _ring.Length * 2) % _ring.Length];

		internal RibbonRing(int points, float step)
		{
			if (points < 2)
			{
				throw new ArgumentOutOfRangeException("points", "A ribbon has at least two points.");
			}
			if (!(step > 0f))
			{
				throw new ArgumentOutOfRangeException("step", "The sample step must be positive.");
			}
			_ring = new T[points];
			Step = step;
		}

		internal void Reset(T start, float now)
		{
			for (int i = 0; i < _ring.Length; i++)
			{
				_ring[i] = start;
			}
			_head = 0;
			_next = now + Step;
		}

		internal void Sample(T position, float now)
		{
			while (now >= _next)
			{
				_head = (_head + 1) % _ring.Length;
				_ring[_head] = position;
				_next += Step;
				if (now - _next > 0.1f)
				{
					_next = now + Step;
				}
			}
			_ring[_head] = position;
		}
	}
	internal static class MarkerMath
	{
		internal const float RevealMargin = 3f;

		internal const float RevealHeight = 2.5f;

		internal static float Reveal(float across, float up, float reach)
		{
			return Clamp01(reach + 3f - across) * Clamp01(2.5f - Math.Abs(up));
		}

		internal static float Sweep(float age, float seconds)
		{
			if (!(seconds <= 0f))
			{
				return Clamp01(age / seconds);
			}
			return 1f;
		}

		internal static float Advance(float phase, float perSecond, float seconds)
		{
			float num = phase + Math.Max(0f, perSecond) * Math.Max(0f, seconds);
			return num - (float)Math.Floor(num);
		}

		internal static float Blink(float sinceTick)
		{
			if (!(sinceTick < 0f))
			{
				return (float)Math.Exp((0f - sinceTick) * 7f);
			}
			return 0f;
		}

		internal static float Clamp01(float v)
		{
			if (!(v < 0f))
			{
				if (!(v > 1f))
				{
					return v;
				}
				return 1f;
			}
			return 0f;
		}
	}
	public sealed class BeamStyle
	{
		public float CoreWidth { get; set; } = 0.03f;

		public float CorePerMetre { get; set; } = 0.0014f;

		public float GlowWidth { get; set; } = 0.34f;

		public float CoreSharpness { get; set; } = 1.1f;

		public float GlowSharpness { get; set; } = 3.2f;

		public float CoreOpacity { get; set; } = 0.9f;

		public float GlowOpacity { get; set; } = 0.45f;

		public bool Column { get; set; } = true;

		public float FlareSize { get; set; }

		public bool FlareAtEnd { get; set; }

		public float FlareOpacity { get; set; } = 0.6f;

		public float FlareLift { get; set; }
	}
	public sealed class Beam
	{
		private static readonly int ColorId = Shader.PropertyToID("_Color");

		private static readonly int HotId = Shader.PropertyToID("_Hot");

		private static readonly int StateId = Shader.PropertyToID("_State");

		private static readonly int ShapeId = Shader.PropertyToID("_Shape");

		private static readonly int RevealId = Shader.PropertyToID("_Reveal");

		private static readonly MaterialPropertyBlock Block = new MaterialPropertyBlock();

		private readonly GameObject _object;

		private readonly LineRenderer _core;

		private readonly LineRenderer _glow;

		private readonly MeshRenderer _flare;

		private Vector3 _from;

		private Vector3 _to;

		private float _born;

		internal bool Live;

		public BeamStyle Style { get; internal set; }

		public Color Colour { get; set; }

		public Color Hot { get; set; }

		public float Opacity { get; set; } = 1f;

		public float Width { get; set; } = 1f;

		public float CoreScale { get; set; } = 1f;

		public float FlareScale { get; set; } = 1f;

		public float CoreLevel { get; set; } = 1f;

		public float GlowLevel { get; set; } = 1f;

		public float FlareLevel { get; set; } = 1f;

		public float GlowWidthScale { get; set; } = 1f;

		public bool Visible { get; private set; }

		public bool Alive
		{
			get
			{
				if (Live && (Object)(object)_object != (Object)null)
				{
					return !((Il2CppObjectBase)_object).WasCollected;
				}
				return false;
			}
		}

		internal GameObject Object => _object;

		internal Beam(GameObject o, LineRenderer core, LineRenderer glow, MeshRenderer flare)
		{
			_object = o;
			_core = core;
			_glow = glow;
			_flare = flare;
		}

		public void Show(Vector3 from, Vector3 to)
		{
			//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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0038: 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)
			if (Alive)
			{
				_from = from;
				_to = to;
				_core.SetPosition(0, from);
				_core.SetPosition(1, to);
				_glow.SetPosition(0, from);
				_glow.SetPosition(1, to);
				if (!Visible)
				{
					Visible = true;
					_object.SetActive(true);
				}
				Draw(Scene.Now);
			}
		}

		public void Hide()
		{
			Visible = false;
			if ((Object)(object)_object != (Object)null && !((Il2CppObjectBase)_object).WasCollected)
			{
				_object.SetActive(false);
			}
		}

		public void Release()
		{
			Beams.Release(this);
		}

		internal void Begin(BeamStyle style, Color colour)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Style = style;
			Colour = colour;
			Hot = Color.Lerp(colour, Color.white, 0.65f);
			float num = (CoreScale = 1f);
			float num3 = (GlowWidthScale = num);
			float num5 = (FlareLevel = num3);
			float num7 = (GlowLevel = num5);
			float num9 = (CoreLevel = num7);
			float num11 = (FlareScale = num9);
			float opacity = (Width = num11);
			Opacity = opacity;
			_born = Scene.Now;
			Visible = false;
			Live = true;
			_object.SetActive(false);
		}

		internal void Draw(float now)
		{
			//IL_0013: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			if (!Visible)
			{
				return;
			}
			float num = now - _born;
			Vector3 val = _to - _from;
			float magnitude = ((Vector3)(ref val)).magnitude;
			float num2 = (Style.Column ? 0f : 1f);
			float num3 = (Scene.HasEye ? DistanceToSegment(Scene.Eye, _from, _to) : 10f);
			_core.widthMultiplier = Math.Max(Style.CoreWidth, num3 * Style.CorePerMetre) * Width * CoreScale;
			_glow.widthMultiplier = Style.GlowWidth * Width * GlowWidthScale;
			Block.SetFloat(RevealId, 0f);
			Block.SetColor(ColorId, Colour);
			Block.SetColor(HotId, Hot);
			Block.SetVector(StateId, new Vector4(num, 0f, 0f, Style.CoreOpacity * Opacity * CoreLevel));
			Block.SetVector(ShapeId, new Vector4(magnitude, 0f, Style.CoreSharpness, num2));
			((Renderer)_core).SetPropertyBlock(Block);
			Block.SetVector(StateId, new Vector4(num, 0f, 0f, Style.GlowOpacity * Opacity * GlowLevel));
			Block.SetVector(ShapeId, new Vector4(magnitude, 0f, Style.GlowSharpness, num2));
			((Renderer)_glow).SetPropertyBlock(Block);
			bool flag = Style.FlareSize > 0f;
			if (((Renderer)_flare).enabled != flag)
			{
				((Renderer)_flare).enabled = flag;
			}
			if (!flag)
			{
				return;
			}
			Vector3 val2 = (Style.FlareAtEnd ? _to : _from);
			Transform transform = ((Component)_flare).transform;
			val2 = (transform.position = val2 + Vector3.up * Style.FlareLift);
			if (Scene.HasEye)
			{
				Vector3 val4 = val2 - Scene.Eye;
				if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f)
				{
					transform.rotation = Quaternion.LookRotation(val4);
				}
			}
			transform.localScale = Vector3.one * (Style.FlareSize * FlareScale);
			Block.SetVector(StateId, new Vector4(num, 0f, 0f, Style.FlareOpacity * Opacity * FlareLevel));
			Block.SetVector(ShapeId, new Vector4(0f, 2f, 0f, 0f));
			((Renderer)_flare).SetPropertyBlock(Block);
		}

		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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0046: 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)
			Vector3 val = b - a;
			float num = ((((Vector3)(ref val)).sqrMagnitude > 1E-06f) ? Mathf.Clamp01(Vector3.Dot(p - a, val) / ((Vector3)(ref val)).sqrMagnitude) : 0f);
			Vector3 val2 = a + val * num - p;
			return ((Vector3)(ref val2)).magnitude;
		}
	}
	public static class Beams
	{
		private static readonly PooledBodies<Beam> Pool = new PooledBodies<Beam>();

		public static Beam? Create(Color colour, BeamStyle style)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			Material val = Shaders.Marker();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Beam beam = Pool.Reuse(Usable) ?? Make(val);
			beam.Begin(style ?? new BeamStyle(), colour);
			Pool.Add(beam);
			return beam;
		}

		private static Beam Make(Material material)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//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_002d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ForgeVisual.Beam");
			Object.DontDestroyOnLoad((Object)(object)val);
			GameObject val2 = new GameObject("flare");
			val2.transform.SetParent(val.transform, false);
			val2.AddComponent<MeshFilter>().sharedMesh = Shaders.Quad();
			MeshRenderer val3 = val2.AddComponent<MeshRenderer>();
			((Renderer)val3).sharedMaterial = material;
			((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)val3).receiveShadows = false;
			LineRenderer glow = Line(val, "glow", material);
			LineRenderer core = Line(val, "core", material);
			return new Beam(val, core, glow, val3);
		}

		internal static LineRenderer Line(GameObject parent, string name, Material material)
		{
			//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)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent.transform, false);
			LineRenderer obj = val.AddComponent<LineRenderer>();
			((Renderer)obj).sharedMaterial = material;
			obj.useWorldSpace = true;
			obj.textureMode = (LineTextureMode)0;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			obj.numCapVertices = 0;
			obj.positionCount = 2;
			return obj;
		}

		internal static void Release(Beam beam)
		{
			if (Pool.Release(beam, delegate(Beam b)
			{
				b.Hide();
			}, Usable(beam)))
			{
				beam.Live = false;
			}
		}

		private static bool Usable(Beam beam)
		{
			if ((Object)(object)beam.Object != (Object)null)
			{
				return !((Il2CppObjectBase)beam.Object).WasCollected;
			}
			return false;
		}

		internal static void TickAll(float now)
		{
			for (int num = Pool.LiveCount - 1; num >= 0; num--)
			{
				Beam beam = Pool[num];
				if (!Usable(beam))
				{
					beam.Live = false;
					Pool.RemoveAt(num);
				}
				else
				{
					beam.Draw(now);
				}
			}
		}

		internal static void ClearAll()
		{
			for (int num = Pool.LiveCount - 1; num >= 0; num--)
			{
				Release(Pool[num]);
			}
		}
	}
	public sealed class WorldBackdrop
	{
		private readonly GameObject _object;

		private readonly Material _material;

		public GameObject Root => _object;

		private WorldBackdrop(GameObject target, Material material)
		{
			_object = target;
			_material = material;
		}

		public static WorldBackdrop? TryCreate(Transform parent, string name, Color color)
		{
			//IL_0017: 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: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Material val2 = new Material(val)
			{
				color = color
			};
			GameObject val3 = new GameObject(name);
			try
			{
				val3.transform.SetParent(parent, false);
				val3.AddComponent<MeshFilter>().sharedMesh = Shaders.Quad();
				MeshRenderer obj = val3.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterial = val2;
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			}
			catch
			{
				Object.Destroy((Object)(object)val3);
				Object.Destroy((Object)(object)val2);
				throw;
			}
			return new WorldBackdrop(val3, val2);
		}

		public void SetColor(Color color)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			_material.color = color;
		}

		public void Place(Vector2 size, Vector2 center, float depth = 0.01f)
		{
			//IL_000b: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			_object.transform.localScale = new Vector3(size.x, size.y, 1f);
			_object.transform.localPosition = new Vector3(center.x, center.y, depth);
		}

		public void Destroy()
		{
			if ((Object)(object)_object != (Object)null && !((Il2CppObjectBase)_object).WasCollected)
			{
				Object.Destroy((Object)(object)_object);
			}
			if ((Object)(object)_material != (Object)null && !((Il2CppObjectBase)_material).WasCollected)
			{
				Object.Destroy((Object)(object)_material);
			}
		}
	}
	public sealed class ImageBoard
	{
		private readonly GameObject _object;

		private readonly Material _material;

		public GameObject Root => _object;

		private ImageBoard(GameObject target, Material material)
		{
			_object = target;
			_material = material;
		}

		public static ImageBoard? TryCreate(Transform parent, string name, int layer, Texture2D texture, float width, float height)
		{
			//IL_0017: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//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_003d: Expected O, but got Unknown
			//IL_0050: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Material val2 = new Material(val)
			{
				color = Color.white,
				mainTexture = (Texture)(object)texture
			};
			GameObject val3 = new GameObject(name)
			{
				layer = layer
			};
			try
			{
				val3.transform.SetParent(parent, false);
				val3.transform.localPosition = Vector3.zero;
				val3.transform.localRotation = Quaternion.identity;
				val3.transform.localScale = new Vector3(width, height, 1f);
				val3.AddComponent<MeshFilter>().sharedMesh = Shaders.Quad();
				MeshRenderer obj = val3.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterial = val2;
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			}
			catch
			{
				Object.Destroy((Object)(object)val3);
				Object.Destroy((Object)(object)val2);
				throw;
			}
			return new ImageBoard(val3, val2);
		}

		public void Destroy()
		{
			if ((Object)(object)_object != (Object)null && !((Il2CppObjectBase)_object).WasCollected)
			{
				Object.Destroy((Object)(object)_object);
			}
			if ((Object)(object)_material != (Object)null && !((Il2CppObjectBase)_material).WasCollected)
			{
				Object.Destroy((Object)(object)_material);
			}
		}
	}
	public sealed class SignBoard
	{
		private readonly Transform _face;

		private readonly float _width;

		private readonly float _height;

		private readonly float _padding;

		private WorldText? _text;

		public WorldBackdrop? Backdrop { get; }

		public WorldText? Text => _text;

		private SignBoard(Transform face, float width, float height, float padding, WorldBackdrop? backdrop)
		{
			_face = face;
			_width = width;
			_height = height;
			_padding = padding;
			Backdrop = backdrop;
		}

		public static SignBoard? TryCreate(Transform face, string backdropName, float width, float height, float padding, Color? backdrop)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_0039: 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)
			WorldBackdrop worldBackdrop = null;
			if (backdrop.HasValue)
			{
				Color valueOrDefault = backdrop.GetValueOrDefault();
				worldBackdrop = WorldBackdrop.TryCreate(face, backdropName, valueOrDefault);
				if (worldBackdrop == null)
				{
					return null;
				}
				worldBackdrop.Place(new Vector2(padding * 2f, padding * 2f), default(Vector2));
			}
			return new SignBoard(face, width, height, padding, worldBackdrop);
		}

		public WorldText ShowText(string textName, WorldTextStyle style, string content, float? lineWidth = null)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (_text == null)
			{
				_text = WorldText.Create(_face, textName, style with
				{
					Alignment = (TextAlignmentOptions)514,
					Pivot = new Vector2(0.5f, 0.5f)
				});
				_text.SetLocalPosition(new Vector3(0f, 0f, -0.02f));
			}
			_text.SetShown(shown: true);
			float num = lineWidth ?? _width;
			Vector2 val = _text.SetContent(content, num, _height);
			Backdrop?.Place(new Vector2(Mathf.Min(num, val.x) + _padding * 2f, val.y + _padding * 2f), default(Vector2));
			return _text;
		}

		public void DestroyText()
		{
			_text?.Destroy();
			_text = null;
		}

		public void Destroy()
		{
			DestroyText();
			Backdrop?.Destroy();
		}
	}
	public sealed class BodyClipRig
	{
		public Transform Root { get; }

		public GameObject Animated { get; }

		public IReadOnlyList<Transform> Bones { get; }

		private BodyClipRig(Transform root, GameObject animated, Transform[] bones)
		{
			Root = root;
			Animated = animated;
			Bones = bones;
		}

		public Transform? Bone(string name)
		{
			for (int i = 0; i < Bones.Count; i++)
			{
				if (((Object)Bones[i]).name == name)
				{
					return Bones[i];
				}
			}
			return null;
		}

		internal static BodyClipRig? Create(Transform root, GameObject animated, string rootBone, string label)
		{
			Transform val = Models.Find(animated.transform, rootBone);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.ErrorOnce("ForgeVisual body clip rig " + label + " has no bone " + rootBone + "; it plays nothing.");
				return null;
			}
			List<Transform> list = new List<Transform> { val };
			foreach (Transform componentsInChild in ((Component)val).GetComponentsInChildren<Transform>(true))
			{
				if ((Object)(object)componentsInChild != (Object)(object)val)
				{
					list.Add(componentsInChild);
				}
			}
			return new BodyClipRig(root, animated, list.ToArray());
		}
	}
	public sealed class BodyClipOptions
	{
		public bool PauseIk { get; set; } = true;

		public bool FirstPersonHead { get; set; }

		public IReadOnlyList<string>? FirstPersonSkip { get; set; }

		public string? Label { get; set; }
	}
	public sealed class BodyClip
	{
		private readonly PlayerAgent _agent;

		private readonly BodyClipRig _rig;

		private readonly bool _local;

		private readonly Transform?[] _game;

		private readonly Behaviour[] _solvers;

		private readonly bool[] _solversWere;

		private readonly Renderer[] _drawn;

		private readonly ShadowCastingMode[] _drawnMode;

		private readonly int[] _drawnLayer;

		private readonly Renderer[] _arms;

		private readonly bool[] _armsWere;

		private bool _posing;

		private bool _firstPerson;

		public int Matched { get; }

		public bool Posing => _posing;

		private BodyClip(PlayerAgent agent, BodyClipRig rig, bool local, Transform?[] game, Behaviour[] solvers, Renderer[] drawn, Renderer[] arms)
		{
			_agent = agent;
			_rig = rig;
			_local = local;
			_game = game;
			_solvers = solvers;
			_solversWere = new bool[solvers.Length];
			_drawn = drawn;
			_drawnMode = (ShadowCastingMode[])(object)new ShadowCastingMode[drawn.Length];
			_drawnLayer = new int[drawn.Length];
			_arms = arms;
			_armsWere = new bool[arms.Length];
			Matched = 0;
			for (int i = 0; i < game.Length; i++)
			{
				if ((Object)(object)game[i] != (Object)null)
				{
					int matched = Matched;
					Matched = matched + 1;
				}
			}
		}

		internal static BodyClip? Bind(PlayerAgent agent, BodyClipRig rig, BodyClipOptions options)
		{
			string text = options.Label;
			if (text == null)
			{
				SNet_Player owner = agent.Owner;
				text = "player " + ((owner != null) ? new ulong?(owner.Lookup) : ((ulong?)null));
			}
			string text2 = text;
			Animator animatorBody = agent.AnimatorBody;
			Transform val = (((Object)(object)animatorBody != (Object)null) ? animatorBody.GetBoneTransform((HumanBodyBones)0) : null);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.ErrorOnce("ForgeVisual body clip " + text2 + ": the player's body has no hips; no clip plays on it.");
				return null;
			}
			Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>(StringComparer.Ordinal);
			foreach (Transform componentsInChild in ((Component)val).GetComponentsInChildren<Transform>(true))
			{
				dictionary.TryAdd(((Object)componentsInChild).name, componentsInChild);
			}
			IReadOnlyList<Transform> bones = rig.Bones;
			Transform[] array = (Transform[])(object)new Transform[bones.Count];
			for (int i = 0; i < bones.Count; i++)
			{
				if (dictionary.TryGetValue(((Object)bones[i]).name, out var value))
				{
					array[i] = value;
				}
			}
			array[0] = val;
			List<Behaviour> list = new List<Behaviour>();
			if (options.PauseIk)
			{
				foreach (MonoBehaviour componentsInChild2 in ((Component)agent).GetComponentsInChildren<MonoBehaviour>(true))
				{
					Type il2CppType = ((Object)componentsInChild2).GetIl2CppType();
					if ((il2CppType.Namespace ?? "").StartsWith("RootMotion.FinalIK", StringComparison.Ordinal) || ((MemberInfo)il2CppType).Name == "PlayerSyncIK")
					{
						list.Add((Behaviour)(object)componentsInChild2);
					}
				}
			}
			bool flag = BodyConvert.IsLocal(agent);
			List<Renderer> list2 = new List<Renderer>();
			List<Renderer> list3 = new List<Renderer>();
			if (flag)
			{
				PlayerSyncModelData playerSyncModel = agent.PlayerSyncModel;
				if ((Object)(object)playerSyncModel != (Object)null)
				{
					HashSet<IntPtr> hashSet = new HashSet<IntPtr>();
					if (!options.FirstPersonHead && playerSyncModel.m_gfxHead != null)
					{
						foreach (GameObject item in (Il2CppArrayBase<GameObject>)(object)playerSyncModel.m_gfxHead)
						{
							if (!((Object)(object)item != (Object)null))
							{
								continue;
							}
							foreach (Renderer componentsInChild3 in item.GetComponentsInChildren<Renderer>(true))
							{
								hashSet.Add(((Il2CppObjectBase)componentsInChild3).Pointer);
							}
						}
					}
					foreach (Renderer componentsInChild4 in ((Component)playerSyncModel).GetComponentsInChildren<Renderer>(true))
					{
						if (!hashSet.Contains(((Il2CppObjectBase)componentsInChild4).Pointer) && !Skipped(((Object)componentsInChild4).name, options.FirstPersonSkip))
						{
							list2.Add(componentsInChild4);
						}
					}
				}
				FirstPersonItemHolder fPItemHolder = agent.FPItemHolder;
				if ((Object)(object)fPItemHolder != (Object)null)
				{
					list3.AddRange((IEnumerable<Renderer>)((Component)fPItemHolder).GetComponentsInChildren<Renderer>(true));
				}
			}
			return new BodyClip(agent, rig, flag, array, list.ToArray(), list2.ToArray(), list3.ToArray());
		}

		private static bool Skipped(string name, IReadOnlyList<string>? skip)
		{
			if (skip == null)
			{
				return false;
			}
			for (int i = 0; i < skip.Count; i++)
			{
				if (name.IndexOf(skip[i], StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		public bool Pose(AnimationClip clip, float time, Vector3 position, Quaternion rotation)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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)
			if (((Il2CppObjectBase)_agent).WasCollected || (Object)(object)_rig.Root == (Object)null || ((Il2CppObjectBase)_rig.Root).WasCollected)
			{
				return false;
			}
			if (!_posing)
			{
				Pause();
			}
			_rig.Root.SetPositionAndRotation(position, rotation);
			clip.SampleAnimation(_rig.Animated, time);
			IReadOnlyList<Transform> bones = _rig.Bones;
			Transform val = _game[0];
			if ((Object)(object)val != (Object)null && !((Il2CppObjectBase)val).WasCollected)
			{
				val.SetPositionAndRotation(bones[0].position, bones[0].rotation);
			}
			for (int i = 1; i < bones.Count; i++)
			{
				Transform val2 = _game[i];
				if ((Object)(object)val2 != (Object)null)
				{
					val2.localRotation = bones[i].localRotation;
				}
			}
			return true;
		}

		public void Stop()
		{
			FirstPerson(on: false);
			if (!_posing)
			{
				return;
			}
			_posing = false;
			for (int i = 0; i < _solvers.Length; i++)
			{
				if ((Object)(object)_solvers[i] != (Object)null && !((Il2CppObjectBase)_solvers[i]).WasCollected && _solversWere[i])
				{
					_solvers[i].enabled = true;
				}
			}
		}

		private void Pause()
		{
			_posing = true;
			for (int i = 0; i < _solvers.Length; i++)
			{
				Behaviour val = _solvers[i];
				_solversWere[i] = (Object)(object)val != (Object)null && !((Il2CppObjectBase)val).WasCollected && val.enabled;
				if (_solversWere[i])
				{
					val.enabled = false;
				}
			}
		}

		public void FirstPerson(bool on, Camera? camera = null)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected I4, but got Unknown
			if (!_local || on == _firstPerson)
			{
				return;
			}
			_firstPerson = on;
			int num = (((Object)(object)camera != (Object)null && !((Il2CppObjectBase)camera).WasCollected) ? camera.cullingMask : (-1));
			for (int i = 0; i < _drawn.Length; i++)
			{
				Renderer val = _drawn[i];
				if ((Object)(object)val == (Object)null || ((Il2CppObjectBase)val).WasCollected)
				{
					continue;
				}
				if (on)
				{
					_drawnMode[i] = (ShadowCastingMode)(int)val.shadowCastingMode;
					_drawnLayer[i] = ((Component)val).gameObject.layer;
					val.shadowCastingMode = (ShadowCastingMode)1;
					if ((num & (1 << ((Component)val).gameObject.layer)) == 0)
					{
						((Component)val).gameObject.layer = 0;
					}
				}
				else
				{
					val.shadowCastingMode = _drawnMode[i];
					((Component)val).gameObject.layer = _drawnLayer[i];
				}
			}
			for (int j = 0; j < _arms.Length; j++)
			{
				Renderer val2 = _arms[j];
				if (!((Object)(object)val2 == (Object)null) && !((Il2CppObjectBase)val2).WasCollected)
				{
					if (on)
					{
						_armsWere[j] = val2.forceRenderingOff;
						val2.forceRenderingOff = true;
					}
					else
					{
						val2.forceRenderingOff = _armsWere[j];
					}
				}
			}
		}
	}
	[Flags]
	public enum BodyParts
	{
		None = 0,
		Head = 1,
		Torso = 2,
		Legs = 4,
		Arms = 8
	}
	public sealed class FirstPersonWearOptions
	{
		public IReadOnlyList<WearBone> Bones { get; set; } = Array.Empty<WearBone>();

		public BodyParts Hide { get; set; } = BodyParts.Head | BodyParts.Torso | BodyParts.Legs;

		public IReadOnlyCollection<string>? FollowParent { get; set; }

		public string? Label { get; set; }
	}
	internal static class BodyConvert
	{
		internal static Vector3 N(Vector3 v)
		{
			//IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(v.x, v.y, v.z);
		}

		internal static Quaternion N(Quaternion q)
		{
			//IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Quaternion(q.x, q.y, q.z, q.w);
		}

		internal static Quaternion U(Quaternion q)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Quaternion(q.X, q.Y, q.Z, q.W);
		}

		internal static Vector3 U(Vector3 v)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(v.X, v.Y, v.Z);
		}

		internal static Dictionary<IntPtr, Matrix4x4> BindRest(Component root, Transform frame)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<IntPtr, Matrix4x4> dictionary = new Dictionary<IntPtr, Matrix4x4>();
			Matrix4x4 worldToLocalMatrix = frame.worldToLocalMatrix;
			foreach (SkinnedMeshRenderer componentsInChild in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
			{
				Mesh val = (((Object)(object)componentsInChild == (Object)null) ? null : componentsInChild.sharedMesh);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Il2CppReferenceArray<Transform> bones = componentsInChild.bones;
				Il2CppStructArray<Matrix4x4> bindposes = val.bindposes;
				if (bones == null || bindposes == null || ((Il2CppArrayBase<Matrix4x4>)(object)bindposes).Length != ((Il2CppArrayBase<Transform>)(object)bones).Length)
				{
					continue;
				}
				Matrix4x4 val2 = worldToLocalMatrix * ((Component)componentsInChild).transform.localToWorldMatrix;
				for (int i = 0; i < ((Il2CppArrayBase<Transform>)(object)bones).Length; i++)
				{
					if ((Object)(object)((Il2CppArrayBase<Transform>)(object)bones)[i] != (Object)null && !dictionary.ContainsKey(((Il2CppObjectBase)((Il2CppArrayBase<Transform>)(object)bones)[i]).Pointer))
					{
						IntPtr pointer = ((Il2CppObjectBase)((Il2CppArrayBase<Transform>)(object)bones)[i]).Pointer;
						Matrix4x4 val3 = ((Il2CppArrayBase<Matrix4x4>)(object)bindposes)[i];
						dictionary[pointer] = val2 * ((Matrix4x4)(ref val3)).inverse;
					}
				}
			}
			return dictionary;
		}

		internal static bool IsLocal(PlayerAgent agent)
		{
			if (((Agent)agent).IsLocallyOwned && (Object)(object)agent.Owner != (Object)null && (Object)(object)SNet.LocalPlayer != (Object)null)
			{
				return agent.Owner.Lookup == SNet.LocalPlayer.Lookup;
			}
			return false;
		}
	}
	public sealed class FirstPersonWear
	{
		private readonly GameObject _root;

		private readonly Transform[] _worn;

		private readonly Transform?[] _on;

		private readonly PlayerFPSBody _body;

		private readonly SkinnedMeshRenderer _renderer;

		private readonly Mesh _mesh;

		private readonly List<Material> _materials = new List<Material>();

		private readonly List<Renderer> _hidden = new List<Renderer>();

		private readonly bool[] _wasOff;

		private readonly GameObject[] _arms;

		private bool _active;

		private bool _shown;

		private bool _held;

		private bool RootAlive
		{
			get
			{
				if ((Object)(object)_root != (Object)null)
				{
					return !((Il2CppObjectBase)_root).WasCollected;
				}
				return false;
			}
		}

		public bool Alive
		{
			get
			{
				if (RootAlive && (Object)(object)_body != (Object)null)
				{
					return !((Il2CppObjectBase)_body).WasCollected;
				}
				return false;
			}
		}

		public bool Active => _active;

		public int Hidden => _hidden.Count;

		private FirstPersonWear(GameObject root, Transform[] worn, Transform?[] on, PlayerFPSBody body, SkinnedMeshRenderer renderer, Mesh mesh, GameObject[] arms, BodyParts hide)
		{
			_root = root;
			_worn = worn;
			_on = on;
			_body = body;
			_renderer = renderer;
			_mesh = mesh;
			_arms = arms;
			foreach (Material item in (Il2CppArrayBase<Material>)(object)((Renderer)renderer).materials)
			{
				_materials.Add(item);
			}
			if ((hide & BodyParts.Torso) != BodyParts.None)
			{
				Collect(body.m_gfxTorso);
			}
			if ((hide & BodyParts.Legs) != BodyParts.None)
			{
				Collect(body.m_gfxLegs);
			}
			if ((hide & BodyParts.Head) != BodyParts.None)
			{
				Collect(body.m_gfxHead);
			}
			if ((hide & BodyParts.Arms) != BodyParts.None)
			{
				Collect(body.m_gfxArms);
			}
			_wasOff = new bool[_hidden.Count];
		}

		internal static FirstPersonWear? Build(PlayerAgent agent, ModelHandle look, FirstPersonWearOptions options)
		{
			//IL_006b: 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)
			string label = options.Label ?? look.Name;
			IReadOnlyList<WearBone> bones = options.Bones;
			if (bones.Count == 0)
			{
				Error(label, "lists no bones");
				return null;
			}
			PlayerFPSBody val = (((Object)(object)agent.FPItemHolder == (Object)null) ? null : agent.FPItemHolder.FPSArms);
			if ((Object)(object)val == (Object)null || ((Il2CppObjectBase)val).WasCollected)
			{
				Error(label, "the player has no first-person body");
				return null;
			}
			GameObject val2 = look.Spawn(Vector3.zero, Quaternion.identity);
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			((Object)val2).name = "ForgeVisual.Wear." + look.Name;
			val2.SetActive(false);
			foreach (Animation componentsInChild in val2.GetComponentsInChildren<Animation>(true))
			{
				((Behaviour)componentsInChild).enabled = false;
			}
			FirstPersonWear firstPersonWear = null;
			try
			{
				firstPersonWear = Bind(agent, val, val2, bones, options, label);
			}
			catch (Exception ex)
			{
				Error(label, "building failed: " + ex);
			}
			if (firstPersonWear == null && (Object)(object)val2 != (Object)null && !((Il2CppObjectBase)val2).WasCollected)
			{
				Object.Destroy((Object)(object)val2);
			}
			return firstPersonWear;
		}

		private static FirstPersonWear? Bind(PlayerAgent agent, PlayerFPSBody body, GameObject root, IReadOnlyList<WearBone> bones, FirstPersonWearOptions options, string label)
		{
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result ty