Decompiled source of IcarusModelReplacement v1.0.0

BepInEx/plugins/IcarusModelReplacement/IcarusModelReplacement.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("IcarusModelReplacement")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2dd13133085a24341e5edad1e8f497dfec2a7318")]
[assembly: AssemblyProduct("IcarusModelReplacement")]
[assembly: AssemblyTitle("IcarusModelReplacement")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace IcarusModelReplacement
{
	internal sealed class Model : IDisposable
	{
		private readonly PackInfo info;

		private readonly Transform[] bones;

		private readonly Vector3[] rest;

		private readonly Vector3[] positions;

		private readonly Vector3[] rotations;

		private readonly MaterialPropertyBlock lighting = new MaterialPropertyBlock();

		private readonly SphericalHarmonicsL2[] probe = (SphericalHarmonicsL2[])(object)new SphericalHarmonicsL2[1];

		private Material material;

		private Mesh mesh;

		private Texture2D texture;

		private SkinnedMeshRenderer renderer;

		private static readonly int Ambient0 = Shader.PropertyToID("_Global_AmbientColor0");

		private static readonly int Ambient1 = Shader.PropertyToID("_Global_AmbientColor1");

		private static readonly int Ambient2 = Shader.PropertyToID("_Global_AmbientColor2");

		public GameObject Root { get; }

		public Model(ModelPack pack, Transform parent, int layer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Expected O, but got Unknown
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Expected O, but got Unknown
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_0437: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Expected O, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_052f: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Standard");
			if ((Object)(object)val == (Object)null || !val.isSupported)
			{
				throw new InvalidOperationException("The game's Standard shader is unavailable.");
			}
			info = pack.Info;
			bones = (Transform[])(object)new Transform[info.Bones.Length];
			rest = (Vector3[])(object)new Vector3[bones.Length];
			positions = (Vector3[])(object)new Vector3[bones.Length + 1];
			rotations = (Vector3[])(object)new Vector3[bones.Length + 1];
			Root = new GameObject(info.Name)
			{
				layer = layer
			};
			Root.SetActive(false);
			Root.transform.SetParent(parent, false);
			Root.transform.localScale = Vector3.one * info.Scale;
			try
			{
				Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[bones.Length];
				for (int i = 0; i < bones.Length; i++)
				{
					BoneInfo boneInfo = info.Bones[i];
					Vector3 val2 = Vector(boneInfo.Position);
					bones[i] = new GameObject(boneInfo.Name)
					{
						layer = layer
					}.transform;
					bones[i].SetParent((boneInfo.Parent < 0) ? Root.transform : bones[boneInfo.Parent], false);
					rest[i] = val2 - ((boneInfo.Parent < 0) ? Vector3.zero : Vector(info.Bones[boneInfo.Parent].Position));
					bones[i].localPosition = rest[i];
					array[i] = Matrix4x4.Translate(-val2);
				}
				Vector3[] array2 = (Vector3[])(object)new Vector3[pack.Vertices.Length];
				Vector3[] array3 = (Vector3[])(object)new Vector3[array2.Length];
				Vector2[] array4 = (Vector2[])(object)new Vector2[array2.Length];
				BoneWeight[] array5 = (BoneWeight[])(object)new BoneWeight[array2.Length];
				for (int j = 0; j < array2.Length; j++)
				{
					Vertex vertex = pack.Vertices[j];
					array2[j] = new Vector3(vertex.X, vertex.Y, vertex.Z);
					array3[j] = new Vector3(vertex.Nx, vertex.Ny, vertex.Nz);
					array4[j] = new Vector2(vertex.U, vertex.V);
					int num = j;
					BoneWeight val3 = default(BoneWeight);
					((BoneWeight)(ref val3)).boneIndex0 = vertex.B0;
					((BoneWeight)(ref val3)).boneIndex1 = vertex.B1;
					((BoneWeight)(ref val3)).boneIndex2 = vertex.B2;
					((BoneWeight)(ref val3)).boneIndex3 = vertex.B3;
					((BoneWeight)(ref val3)).weight0 = vertex.W0;
					((BoneWeight)(ref val3)).weight1 = vertex.W1;
					((BoneWeight)(ref val3)).weight2 = vertex.W2;
					((BoneWeight)(ref val3)).weight3 = vertex.W3;
					array5[num] = val3;
				}
				mesh = new Mesh
				{
					name = info.Name,
					indexFormat = (IndexFormat)1
				};
				mesh.vertices = array2;
				mesh.normals = array3;
				mesh.uv = array4;
				mesh.boneWeights = array5;
				mesh.bindposes = array;
				mesh.triangles = pack.Indices;
				mesh.RecalculateBounds();
				mesh.UploadMeshData(true);
				texture = new Texture2D(2, 2, (TextureFormat)4, true)
				{
					name = info.Name,
					filterMode = (FilterMode)2,
					wrapMode = (TextureWrapMode)1
				};
				if (!ImageConversion.LoadImage(texture, pack.Texture, true))
				{
					throw new InvalidOperationException("Cannot decode model texture.");
				}
				material = new Material(val)
				{
					name = info.Name,
					mainTexture = (Texture)(object)texture,
					color = Color.white
				};
				material.SetFloat("_Metallic", info.Material.Metallic);
				material.SetFloat("_Glossiness", info.Material.Smoothness);
				if (!info.Material.SpecularHighlights)
				{
					material.SetFloat("_SpecularHighlights", 0f);
					material.EnableKeyword("_SPECULARHIGHLIGHTS_OFF");
				}
				if (info.Material.Emission > 0f)
				{
					material.EnableKeyword("_EMISSION");
					material.SetTexture("_EmissionMap", (Texture)(object)texture);
					float emission = info.Material.Emission;
					material.SetVector("_EmissionColor", new Vector4(emission, emission, emission, 1f));
				}
				renderer = Root.AddComponent<SkinnedMeshRenderer>();
				renderer.sharedMesh = mesh;
				((Renderer)renderer).sharedMaterial = material;
				renderer.bones = bones;
				renderer.rootBone = Root.transform;
				renderer.quality = (SkinQuality)4;
				((Renderer)renderer).lightProbeUsage = (LightProbeUsage)4;
				Bounds bounds = mesh.bounds;
				((Bounds)(ref bounds)).Expand(info.BoundsPadding * 2f);
				((Renderer)renderer).localBounds = bounds;
				Animate(Motion.Sample(0.0, 0f, 0f, 0f));
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		private static Vector3 Vector(float[] v)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(v[0], v[1], v[2]);
		}

		public void UpdateLighting()
		{
			//IL_0005: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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)
			Color val = (Shader.GetGlobalColor(Ambient0) + Shader.GetGlobalColor(Ambient1) + Shader.GetGlobalColor(Ambient2)) / 3f;
			val.r = Mathf.Max(0.12f, val.r);
			val.g = Mathf.Max(0.12f, val.g);
			val.b = Mathf.Max(0.12f, val.b);
			probe[0] = RenderSettings.ambientProbe;
			((SphericalHarmonicsL2)(ref probe[0])).AddAmbientLight(val);
			lighting.CopySHCoefficientArraysFrom(probe);
			((Renderer)renderer).SetPropertyBlock(lighting);
		}

		public void Animate(Motion state)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			Array.Clear(positions, 0, positions.Length);
			Array.Clear(rotations, 0, rotations.Length);
			MotionInfo[] motions = info.Motions;
			foreach (MotionInfo motionInfo in motions)
			{
				float num = state.Get(motionInfo.Kind);
				ref Vector3 reference = ref positions[motionInfo.Index];
				reference += Vector(motionInfo.Position) * num;
				ref Vector3 reference2 = ref rotations[motionInfo.Index];
				reference2 += Vector(motionInfo.Rotation) * num;
			}
			for (int j = 0; j < bones.Length; j++)
			{
				bones[j].localPosition = rest[j] + positions[j];
				bones[j].localRotation = Quaternion.Euler(rotations[j]);
			}
			Root.transform.localPosition = Vector(info.Offset) + positions[bones.Length];
			Root.transform.localRotation = Quaternion.Euler(Vector(info.Rotation)) * Quaternion.Euler(rotations[bones.Length]);
		}

		public void Dispose()
		{
			if ((Object)(object)Root != (Object)null)
			{
				Root.SetActive(false);
				Object.Destroy((Object)(object)Root);
			}
			if ((Object)(object)mesh != (Object)null)
			{
				Object.Destroy((Object)(object)mesh);
			}
			if ((Object)(object)material != (Object)null)
			{
				Object.Destroy((Object)(object)material);
			}
			if ((Object)(object)texture != (Object)null)
			{
				Object.Destroy((Object)(object)texture);
			}
		}
	}
	[DataContract]
	internal sealed class PackInfo
	{
		[DataMember(Name = "format", IsRequired = true)]
		public int Format { get; set; }

		[DataMember(Name = "name", IsRequired = true)]
		public string Name { get; set; }

		[DataMember(Name = "author", IsRequired = true)]
		public string Author { get; set; }

		[DataMember(Name = "license", IsRequired = true)]
		public string License { get; set; }

		[DataMember(Name = "source")]
		public string Source { get; set; }

		[DataMember(Name = "scale", IsRequired = true)]
		public float Scale { get; set; }

		[DataMember(Name = "offset")]
		public float[] Offset { get; set; }

		[DataMember(Name = "rotation")]
		public float[] Rotation { get; set; }

		[DataMember(Name = "boundsPadding")]
		public float BoundsPadding { get; set; }

		[DataMember(Name = "material")]
		public MaterialInfo Material { get; set; }

		[DataMember(Name = "bones", IsRequired = true)]
		public BoneInfo[] Bones { get; set; }

		[DataMember(Name = "motions")]
		public MotionInfo[] Motions { get; set; }
	}
	[DataContract]
	internal sealed class BoneInfo
	{
		[DataMember(Name = "name", IsRequired = true)]
		public string Name { get; set; }

		[DataMember(Name = "parent", IsRequired = true)]
		public int Parent { get; set; }

		[DataMember(Name = "position", IsRequired = true)]
		public float[] Position { get; set; }
	}
	[DataContract]
	internal sealed class MaterialInfo
	{
		[DataMember(Name = "smoothness")]
		public float Smoothness { get; set; }

		[DataMember(Name = "metallic")]
		public float Metallic { get; set; }

		[DataMember(Name = "emission")]
		public float Emission { get; set; }

		[DataMember(Name = "specularHighlights")]
		public bool SpecularHighlights { get; set; }
	}
	[DataContract]
	internal sealed class MotionInfo
	{
		public int Index;

		public Signal Kind;

		[DataMember(Name = "target", IsRequired = true)]
		public string Target { get; set; }

		[DataMember(Name = "signal", IsRequired = true)]
		public string Signal { get; set; }

		[DataMember(Name = "position")]
		public float[] Position { get; set; }

		[DataMember(Name = "rotation")]
		public float[] Rotation { get; set; }
	}
	internal struct Vertex
	{
		public float X;

		public float Y;

		public float Z;

		public float Nx;

		public float Ny;

		public float Nz;

		public float U;

		public float V;

		public byte B0;

		public byte B1;

		public byte B2;

		public byte B3;

		public float W0;

		public float W1;

		public float W2;

		public float W3;
	}
	internal sealed class ModelPack
	{
		public PackInfo Info;

		public Vertex[] Vertices;

		public int[] Indices;

		public byte[] Texture;

		public static ModelPack Load(string directory)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			ModelPack modelPack = new ModelPack();
			using (FileStream fileStream = Open(directory, "model.json", 1048576L))
			{
				modelPack.Info = (PackInfo)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(PackInfo), new DataContractJsonSerializerSettings
				{
					MaxItemsInObjectGraph = 20000
				})).ReadObject((Stream)fileStream);
			}
			modelPack.ValidateInfo();
			using (FileStream stream = Open(directory, "mesh.bin.gz", 33554432L))
			{
				using GZipStream input = new GZipStream(stream, CompressionMode.Decompress);
				using BinaryReader reader = new BinaryReader(input);
				modelPack.ReadMesh(reader);
			}
			using (FileStream fileStream2 = Open(directory, "texture.png", 67108864L))
			{
				using BinaryReader binaryReader = new BinaryReader(fileStream2);
				modelPack.Texture = binaryReader.ReadBytes((int)fileStream2.Length);
			}
			modelPack.ValidateTexture();
			return modelPack;
		}

		private static FileStream Open(string directory, string name, long limit)
		{
			string path = Path.Combine(directory, name);
			Require((File.GetAttributes(path) & FileAttributes.ReparsePoint) == 0, "Asset must be a regular file: " + name);
			FileStream fileStream = File.OpenRead(path);
			if (fileStream.Length > 0 && fileStream.Length <= limit)
			{
				return fileStream;
			}
			fileStream.Dispose();
			throw new InvalidDataException("Asset size limit exceeded or empty: " + name);
		}

		private static void Require(bool condition, string message)
		{
			if (!condition)
			{
				throw new InvalidDataException(message);
			}
		}

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		private static void Range(float value, float min, float max, string name)
		{
			Require(Finite(value) && value >= min && value <= max, "Invalid " + name);
		}

		private static float[] Vector(float[] value, bool required = false)
		{
			if (value == null && !required)
			{
				return new float[3];
			}
			Require(value != null && value.Length == 3, "Expected a three-component vector");
			for (int i = 0; i < value.Length; i++)
			{
				Range(value[i], -1000f, 1000f, "vector component");
			}
			return value;
		}

		private void ValidateInfo()
		{
			Require(Info != null && Info.Format == 1, "Unsupported model format");
			Require(!string.IsNullOrWhiteSpace(Info.Name) && !string.IsNullOrWhiteSpace(Info.Author) && !string.IsNullOrWhiteSpace(Info.License), "Model name, author and license are required");
			Range(Info.Scale, 0.001f, 100f, "scale");
			Range(Info.BoundsPadding, 0f, 100f, "bounds padding");
			Info.Offset = Vector(Info.Offset);
			Info.Rotation = Vector(Info.Rotation);
			Info.Material = Info.Material ?? new MaterialInfo();
			Range(Info.Material.Smoothness, 0f, 1f, "smoothness");
			Range(Info.Material.Metallic, 0f, 1f, "metallic");
			Range(Info.Material.Emission, 0f, 2f, "emission");
			Require(Info.Bones != null && Info.Bones.Length >= 1 && Info.Bones.Length <= 256, "Bone count must be 1..256");
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int i = 0; i < Info.Bones.Length; i++)
			{
				BoneInfo boneInfo = Info.Bones[i];
				Require(boneInfo != null && !string.IsNullOrWhiteSpace(boneInfo.Name) && boneInfo.Name.Length <= 128 && boneInfo.Name != "$root" && !dictionary.ContainsKey(boneInfo.Name), "Invalid or duplicate bone name");
				Require(boneInfo.Parent >= -1 && boneInfo.Parent < i, "Bone parents must precede children");
				boneInfo.Position = Vector(boneInfo.Position, required: true);
				dictionary.Add(boneInfo.Name, i);
			}
			dictionary.Add("$root", Info.Bones.Length);
			Info.Motions = Info.Motions ?? Array.Empty<MotionInfo>();
			Require(Info.Motions.Length <= 1024, "Too many motion bindings");
			MotionInfo[] motions = Info.Motions;
			foreach (MotionInfo motionInfo in motions)
			{
				Require(motionInfo != null && motionInfo.Target != null && dictionary.TryGetValue(motionInfo.Target, out motionInfo.Index), "Unknown motion target");
				Require(Enum.TryParse<Signal>(motionInfo.Signal, out motionInfo.Kind) && Enum.GetName(typeof(Signal), motionInfo.Kind) == motionInfo.Signal, "Unknown motion signal");
				motionInfo.Position = Vector(motionInfo.Position);
				motionInfo.Rotation = Vector(motionInfo.Rotation);
			}
		}

		private static float ReadFloat(BinaryReader reader)
		{
			float num = reader.ReadSingle();
			Require(Finite(num), "Non-finite mesh value");
			return num;
		}

		private void ReadMesh(BinaryReader reader)
		{
			Require(reader.ReadUInt32() == 1145918025 && reader.ReadInt32() == 1, "Unsupported mesh format");
			int num = reader.ReadInt32();
			int num2 = reader.ReadInt32();
			Require(num >= 3 && num <= 250000 && num2 >= 3 && num2 <= 1500000 && num2 % 3 == 0, "Mesh size limit exceeded");
			Vertices = new Vertex[num];
			for (int i = 0; i < num; i++)
			{
				Vertex vertex = new Vertex
				{
					X = ReadFloat(reader),
					Y = ReadFloat(reader),
					Z = ReadFloat(reader),
					Nx = ReadFloat(reader),
					Ny = ReadFloat(reader),
					Nz = ReadFloat(reader),
					U = ReadFloat(reader),
					V = ReadFloat(reader),
					B0 = reader.ReadByte(),
					B1 = reader.ReadByte(),
					B2 = reader.ReadByte(),
					B3 = reader.ReadByte(),
					W0 = ReadFloat(reader),
					W1 = ReadFloat(reader),
					W2 = ReadFloat(reader),
					W3 = ReadFloat(reader)
				};
				Require(Math.Abs(vertex.X) <= 1000f && Math.Abs(vertex.Y) <= 1000f && Math.Abs(vertex.Z) <= 1000f, "Mesh coordinate out of range");
				Require(Math.Abs(vertex.Nx * vertex.Nx + vertex.Ny * vertex.Ny + vertex.Nz * vertex.Nz - 1f) < 0.01f, "Mesh normals must be unit length");
				Require(vertex.U >= 0f && vertex.U <= 1f && vertex.V >= 0f && vertex.V <= 1f, "Atlas UV out of range");
				Require(vertex.B0 < Info.Bones.Length && vertex.B1 < Info.Bones.Length && vertex.B2 < Info.Bones.Length && vertex.B3 < Info.Bones.Length, "Mesh bone index out of range");
				Require(vertex.W0 >= vertex.W1 && vertex.W1 >= vertex.W2 && vertex.W2 >= vertex.W3 && vertex.W3 >= 0f && Math.Abs(vertex.W0 + vertex.W1 + vertex.W2 + vertex.W3 - 1f) < 1E-05f, "Skin weights must be sorted and normalized");
				Vertices[i] = vertex;
			}
			Indices = new int[num2];
			for (int j = 0; j < num2; j++)
			{
				Indices[j] = reader.ReadInt32();
				Require(Indices[j] >= 0 && Indices[j] < num, "Triangle index out of range");
			}
			Require(reader.BaseStream.ReadByte() == -1, "Unexpected trailing mesh data");
		}

		private void ValidateTexture()
		{
			byte[] array = new byte[16]
			{
				137, 80, 78, 71, 13, 10, 26, 10, 0, 0,
				0, 13, 73, 72, 68, 82
			};
			Require(Texture.Length >= 33, "Truncated PNG");
			for (int i = 0; i < array.Length; i++)
			{
				Require(Texture[i] == array[i], "Expected PNG with IHDR");
			}
			uint num = BigEndian(16);
			uint num2 = BigEndian(20);
			Require(num != 0 && num2 != 0 && num <= 8192 && num2 <= 8192 && (ulong)((long)num * (long)num2) <= 16777216uL, "Texture exceeds 16 megapixels");
		}

		private uint BigEndian(int at)
		{
			return (uint)((Texture[at] << 24) | (Texture[at + 1] << 16) | (Texture[at + 2] << 8) | Texture[at + 3]);
		}
	}
	internal enum Signal
	{
		Constant,
		Stride,
		Step,
		LeftStep,
		RightStep,
		Air,
		Sail
	}
	internal struct Motion
	{
		private float stride;

		private float air;

		private float sail;

		public static Motion Sample(double phase, float run, float air, float sail)
		{
			return new Motion
			{
				stride = (float)Math.Sin(phase) * run * (1f - air),
				air = air,
				sail = sail
			};
		}

		public float Get(Signal signal)
		{
			return signal switch
			{
				Signal.Constant => 1f, 
				Signal.Stride => stride, 
				Signal.Step => Math.Abs(stride), 
				Signal.LeftStep => Math.Max(0f, stride), 
				Signal.RightStep => Math.Max(0f, 0f - stride), 
				Signal.Air => air, 
				Signal.Sail => sail, 
				_ => throw new ArgumentOutOfRangeException("signal"), 
			};
		}
	}
	[BepInPlugin("org.fyyy.icarusmodelreplacement", "Icarus Model Replacement", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private struct HiddenRenderer
		{
			private Renderer renderer;

			private bool wasHidden;

			public void Set(Renderer next)
			{
				if (!((Object)(object)renderer == (Object)(object)next))
				{
					if ((Object)(object)renderer != (Object)null)
					{
						renderer.forceRenderingOff = wasHidden;
					}
					renderer = next;
					if ((Object)(object)renderer != (Object)null)
					{
						wasHidden = renderer.forceRenderingOff;
						renderer.forceRenderingOff = true;
					}
				}
			}
		}

		private const string Builtin = "builtin";

		private MechaArmorModel armor;

		private Model model;

		private ConfigEntry<string> modelDirectory;

		private string selected;

		private HiddenRenderer[] parts = Array.Empty<HiddenRenderer>();

		private HiddenRenderer[] bones = Array.Empty<HiddenRenderer>();

		private HiddenRenderer[] wrecks = Array.Empty<HiddenRenderer>();

		private GameObject wreckageGroup;

		private void Awake()
		{
			modelDirectory = ((BaseUnityPlugin)this).Config.Bind<string>("Model", "Directory", "builtin", "builtin uses the included Gugugaga. Otherwise, a model folder relative to BepInEx/plugins or absolute. Empty keeps vanilla Icarus. Changes apply in game.");
		}

		private void LateUpdate()
		{
			Player val = (GameMain.isRunning ? GameMain.mainPlayer : null);
			MechaArmorModel val2 = ((val != null) ? val.mechaArmorModel : null);
			if ((Object)(object)val2 != (Object)null && !((ManualBehaviour)val2).inited)
			{
				val2 = null;
			}
			string text = modelDirectory.Value.Trim();
			if (armor != val2 || selected != text)
			{
				Clear();
				armor = val2;
				selected = text;
				if ((Object)(object)armor != (Object)null && text.Length != 0)
				{
					try
					{
						SkinnedMeshRenderer[] componentsInChildren = ((Component)armor).GetComponentsInChildren<SkinnedMeshRenderer>(true);
						ModelPack modelPack = ModelPack.Load((text == "builtin") ? Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "model") : Path.Combine(Paths.PluginPath, text));
						model = new Model(modelPack, val.controller.model, ((Component)armor).gameObject.layer);
						Renderer[] renderers = (Renderer[])(object)componentsInChildren;
						parts = Hide(renderers);
						bones = new HiddenRenderer[armor.boneModels.Length];
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Model attached: " + modelPack.Info.Name + " by " + modelPack.Info.Author + " (" + modelPack.Info.License + ")."));
					}
					catch (Exception arg)
					{
						Clear();
						((BaseUnityPlugin)this).Logger.LogError((object)$"Cannot load model '{text}'; keeping Icarus. {arg}");
						return;
					}
				}
			}
			if ((Object)(object)armor == (Object)null || model == null)
			{
				return;
			}
			for (int i = 0; i < bones.Length; i++)
			{
				bones[i].Set((Renderer)(object)armor.boneModels[i]?.meshRenderer);
			}
			if ((Object)(object)wreckageGroup != (Object)(object)armor.wreckageGroup)
			{
				Restore(wrecks);
				wreckageGroup = armor.wreckageGroup;
				HiddenRenderer[] array;
				if (!((Object)(object)wreckageGroup != (Object)null))
				{
					array = Array.Empty<HiddenRenderer>();
				}
				else
				{
					Renderer[] renderers = (Renderer[])(object)wreckageGroup.GetComponentsInChildren<MeshRenderer>(true);
					array = Hide(renderers);
				}
				wrecks = array;
			}
			model.Root.SetActive(((ManualBehaviour)armor).active && val.isAlive);
			model.UpdateLighting();
			PlayerAnimator animator = val.animator;
			if (!((TrackedReference)(object)animator.run_slow == (TrackedReference)null))
			{
				float air = Mathf.Clamp01(animator.driftWeight + animator.flyWeight + animator.sailWeight);
				Motion state = Motion.Sample((double)animator.run_slow.normalizedTime * Math.PI * 2.0, Mathf.Clamp01(animator.runWeight), air, Mathf.Clamp01(animator.sailWeight));
				model.Animate(state);
			}
		}

		private static HiddenRenderer[] Hide(Renderer[] renderers)
		{
			HiddenRenderer[] array = new HiddenRenderer[renderers.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Set(renderers[i]);
			}
			return array;
		}

		private static void Restore(HiddenRenderer[] renderers)
		{
			for (int i = 0; i < renderers.Length; i++)
			{
				renderers[i].Set(null);
			}
		}

		private void OnDisable()
		{
			Clear();
			armor = null;
		}

		private void Clear()
		{
			Restore(parts);
			Restore(bones);
			Restore(wrecks);
			parts = (bones = (wrecks = Array.Empty<HiddenRenderer>()));
			model?.Dispose();
			model = null;
			wreckageGroup = null;
		}
	}
}