Decompiled source of ModelKit v1.0.1

BepInEx/plugins/ModelKit.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace HtfModelKit;

public abstract class AssetSource
{
	private sealed class DiskSource : AssetSource
	{
		private readonly string _dir;

		public override string Describe => _dir;

		public DiskSource(string dir)
		{
			_dir = dir;
		}

		public override byte[] Read(string relative)
		{
			if (string.IsNullOrEmpty(_dir))
			{
				return null;
			}
			try
			{
				string path = _dir + "/" + relative;
				return (!File.Exists(path)) ? null : File.ReadAllBytes(path);
			}
			catch (Exception e)
			{
				Kit.Ex("AssetSource.Folder(" + relative + ")", e);
				return null;
			}
		}
	}

	private sealed class ResourceSource : AssetSource
	{
		private readonly Assembly _asm;

		private readonly string _prefix;

		public override string Describe => "built into " + ((!(_asm == null)) ? _asm.GetName().Name : "?");

		public ResourceSource(Assembly asm, string prefix)
		{
			_asm = asm;
			_prefix = prefix ?? "";
		}

		public override byte[] Read(string relative)
		{
			if (_asm == null)
			{
				return null;
			}
			try
			{
				string name = _prefix + relative.Replace('/', '.');
				using Stream stream = _asm.GetManifestResourceStream(name);
				if (stream == null)
				{
					return null;
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				return array;
			}
			catch (Exception e)
			{
				Kit.Ex("AssetSource.Embedded(" + relative + ")", e);
				return null;
			}
		}
	}

	private sealed class Chain : AssetSource
	{
		private readonly AssetSource _first;

		private readonly AssetSource _second;

		public override string Describe => _first.Describe + " then " + _second.Describe;

		public Chain(AssetSource a, AssetSource b)
		{
			_first = a;
			_second = b;
		}

		public override byte[] Read(string relative)
		{
			byte[] array = _first.Read(relative);
			return array ?? _second.Read(relative);
		}

		public override byte[] ReadOrInflate(string relative)
		{
			byte[] array = _first.ReadOrInflate(relative);
			return array ?? _second.ReadOrInflate(relative);
		}
	}

	public abstract string Describe { get; }

	public abstract byte[] Read(string relative);

	public AssetSource Then(AssetSource fallback)
	{
		return (fallback != null) ? new Chain(this, fallback) : this;
	}

	public static AssetSource Folder(string path)
	{
		return new DiskSource(path);
	}

	public static AssetSource Embedded(Assembly assembly, string prefix)
	{
		return new ResourceSource(assembly, prefix);
	}

	public virtual byte[] ReadOrInflate(string relative)
	{
		byte[] array = Read(relative);
		if (array != null)
		{
			return array;
		}
		return Inflate(Read(relative + ".gz"));
	}

	public string ReadText(string relative)
	{
		byte[] array = ReadOrInflate(relative);
		if (array == null)
		{
			return null;
		}
		try
		{
			return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetString(array);
		}
		catch (Exception e)
		{
			Kit.Ex("AssetSource.ReadText(" + relative + ")", e);
			return null;
		}
	}

	public bool Has(string relative)
	{
		return ReadOrInflate(relative) != null;
	}

	internal static byte[] Inflate(byte[] compressed)
	{
		if (compressed == null)
		{
			return null;
		}
		try
		{
			using MemoryStream stream = new MemoryStream(compressed);
			using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[16384];
			int count;
			while ((count = gZipStream.Read(array, 0, array.Length)) > 0)
			{
				memoryStream.Write(array, 0, count);
			}
			return memoryStream.ToArray();
		}
		catch (Exception ex)
		{
			Kit.Warn("could not decompress an asset: " + ex.Message);
			return null;
		}
	}
}
public static class Kit
{
	public const string Tag = "[ModelKit] ";

	private static Action<string> _info;

	private static Action<string> _warn;

	public static void UseLogger(Action<string> info, Action<string> warn)
	{
		_info = info;
		_warn = warn;
	}

	public static void Info(string message)
	{
		try
		{
			if (_info != null)
			{
				_info(message);
			}
			else
			{
				Debug.Log((object)("[ModelKit] " + message));
			}
		}
		catch
		{
		}
	}

	public static void Warn(string message)
	{
		try
		{
			if (_warn != null)
			{
				_warn(message);
			}
			else
			{
				Debug.LogWarning((object)("[ModelKit] " + message));
			}
		}
		catch
		{
		}
	}

	public static void Ex(string where, Exception e)
	{
		try
		{
			Warn(where + " failed: " + ((e != null) ? (e.GetType().Name + ": " + e.Message) : "(no detail)"));
		}
		catch
		{
		}
	}
}
public static class Materials
{
	private static readonly string[] PlainShaders = new string[6] { "Universal Render Pipeline/Lit", "Universal Render Pipeline/Simple Lit", "Universal Render Pipeline/Baked Lit", "Universal Render Pipeline/Unlit", "Standard", "Legacy Shaders/Diffuse" };

	private static Shader _plain;

	private static bool _plainTried;

	public static Shader PlainShader()
	{
		if (_plainTried)
		{
			return _plain;
		}
		_plainTried = true;
		for (int i = 0; i < PlainShaders.Length; i++)
		{
			if (!((Object)(object)_plain == (Object)null))
			{
				break;
			}
			try
			{
				_plain = Shader.Find(PlainShaders[i]);
			}
			catch
			{
			}
		}
		if ((Object)(object)_plain == (Object)null)
		{
			Kit.Warn("no plain lit shader was found in this build; materials will be cloned as-is");
		}
		return _plain;
	}

	public static bool IsPlainShader(Shader s)
	{
		if ((Object)(object)s == (Object)null)
		{
			return false;
		}
		for (int i = 0; i < PlainShaders.Length; i++)
		{
			if (((Object)s).name == PlainShaders[i])
			{
				return true;
			}
		}
		return false;
	}

	public static Material FindTemplate(GameObject drawnByTheGame)
	{
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Expected O, but got Unknown
		Material val = null;
		try
		{
			if ((Object)(object)drawnByTheGame != (Object)null)
			{
				Renderer[] componentsInChildren = drawnByTheGame.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					Material val3 = ((!((Object)(object)val2 == (Object)null)) ? val2.sharedMaterial : null);
					if (!((Object)(object)val3 == (Object)null))
					{
						if ((Object)(object)val == (Object)null)
						{
							val = val3;
						}
						if (IsPlainShader(val3.shader))
						{
							return val3;
						}
					}
				}
			}
		}
		catch (Exception e)
		{
			Kit.Ex("Materials.FindTemplate", e);
		}
		Shader val4 = PlainShader();
		if ((Object)(object)val4 != (Object)null)
		{
			Kit.Info("no plain-shaded material to copy, so one was built from '" + ((Object)val4).name + "'");
			return new Material(val4);
		}
		return val;
	}

	public static Material[] Build(ModelData model, Material template, bool calm)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Expected O, but got Unknown
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Expected O, but got Unknown
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		if (model == null || model.MaterialNames == null)
		{
			return (Material[])(object)new Material[0];
		}
		if ((Object)(object)template == (Object)null)
		{
			Shader val = PlainShader();
			if ((Object)(object)val == (Object)null)
			{
				Kit.Warn("no template and no plain shader; cannot build materials");
				return (Material[])(object)new Material[0];
			}
			template = new Material(val);
		}
		Material[] array = (Material[])(object)new Material[model.MaterialNames.Length];
		for (int i = 0; i < array.Length; i++)
		{
			Material val2 = new Material(template);
			((Object)val2).name = "ModelKit_" + model.MaterialNames[i];
			if (calm)
			{
				Calm(val2);
			}
			if ((Object)(object)model.Textures[i] != (Object)null)
			{
				SetTexture(val2, (Texture)(object)model.Textures[i]);
				SetColor(val2, Color.white);
				if (model.Cutout[i])
				{
					EnableCutout(val2);
				}
			}
			else
			{
				SetTexture(val2, (Texture)(object)Texture2D.whiteTexture);
				SetColor(val2, model.Colors[i]);
			}
			array[i] = val2;
			Texture val3 = (Texture)(object)model.Textures[i];
			Kit.Info("  material " + (i + 1) + "/" + array.Length + " '" + model.MaterialNames[i] + "': " + ((!((Object)(object)val3 != (Object)null)) ? ("NO TEXTURE - drawn flat in " + ColorHex(model.Colors[i])) : ("texture " + ((Object)val3).name + " " + val3.width + "x" + val3.height)) + ((!model.Cutout[i]) ? "" : "  (cutout)"));
		}
		return array;
	}

	public static void SetTexture(Material m, Texture tex)
	{
		if (!((Object)(object)m == (Object)null))
		{
			if (m.HasProperty("_BaseMap"))
			{
				m.SetTexture("_BaseMap", tex);
			}
			if (m.HasProperty("_MainTex"))
			{
				m.SetTexture("_MainTex", tex);
			}
			m.mainTexture = tex;
		}
	}

	public static void SetColor(Material m, Color c)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)m == (Object)null))
		{
			if (m.HasProperty("_BaseColor"))
			{
				m.SetColor("_BaseColor", c);
			}
			if (m.HasProperty("_Color"))
			{
				m.SetColor("_Color", c);
			}
		}
	}

	public static void Calm(Material m)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)m == (Object)null)
		{
			return;
		}
		try
		{
			m.DisableKeyword("_EMISSION");
			if (m.HasProperty("_EmissionColor"))
			{
				m.SetColor("_EmissionColor", Color.black);
			}
			if (m.HasProperty("_EmissionMap"))
			{
				m.SetTexture("_EmissionMap", (Texture)null);
			}
			m.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)4;
			if (m.HasProperty("_MainTex"))
			{
				m.SetTextureOffset("_MainTex", Vector2.zero);
			}
			if (m.HasProperty("_BaseMap"))
			{
				m.SetTextureOffset("_BaseMap", Vector2.zero);
			}
			if (m.HasProperty("_Metallic"))
			{
				m.SetFloat("_Metallic", 0f);
			}
			if (m.HasProperty("_Smoothness"))
			{
				m.SetFloat("_Smoothness", 0.1f);
			}
			if (m.HasProperty("_Glossiness"))
			{
				m.SetFloat("_Glossiness", 0.1f);
			}
			string[] array = new string[9] { "_BumpMap", "_NormalMap", "_MetallicGlossMap", "_SpecGlossMap", "_ParallaxMap", "_OcclusionMap", "_DetailAlbedoMap", "_DetailNormalMap", "_DetailMask" };
			for (int i = 0; i < array.Length; i++)
			{
				if (m.HasProperty(array[i]))
				{
					m.SetTexture(array[i], (Texture)null);
				}
			}
		}
		catch (Exception e)
		{
			Kit.Ex("Materials.Calm", e);
		}
	}

	public static void EnableCutout(Material m)
	{
		if ((Object)(object)m == (Object)null)
		{
			return;
		}
		try
		{
			m.EnableKeyword("_ALPHATEST_ON");
			if (m.HasProperty("_Cutoff"))
			{
				m.SetFloat("_Cutoff", 0.5f);
			}
			if (m.HasProperty("_AlphaClip"))
			{
				m.SetFloat("_AlphaClip", 1f);
			}
			if (m.HasProperty("_Surface"))
			{
				m.SetFloat("_Surface", 0f);
			}
			m.renderQueue = 2450;
		}
		catch (Exception e)
		{
			Kit.Ex("Materials.EnableCutout", e);
		}
	}

	public static void Describe(Material m)
	{
		try
		{
			if ((Object)(object)m == (Object)null || (Object)(object)m.shader == (Object)null)
			{
				Kit.Info("no template material");
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("template shader '").Append(((Object)m.shader).name).Append("'");
			if (m.HasProperty("_Metallic"))
			{
				stringBuilder.Append(", metallic ").Append(m.GetFloat("_Metallic").ToString("0.##"));
			}
			if (m.HasProperty("_Smoothness"))
			{
				stringBuilder.Append(", smoothness ").Append(m.GetFloat("_Smoothness").ToString("0.##"));
			}
			if (m.HasProperty("_BumpMap") && (Object)(object)m.GetTexture("_BumpMap") != (Object)null)
			{
				stringBuilder.Append(", bump map");
			}
			if (m.HasProperty("_MetallicGlossMap") && (Object)(object)m.GetTexture("_MetallicGlossMap") != (Object)null)
			{
				stringBuilder.Append(", metallic map");
			}
			if (m.IsKeywordEnabled("_EMISSION"))
			{
				stringBuilder.Append(", emission ON");
			}
			Kit.Info(stringBuilder.ToString());
		}
		catch (Exception e)
		{
			Kit.Ex("Materials.Describe", e);
		}
	}

	private static string ColorHex(Color c)
	{
		return "#" + Mathf.RoundToInt(c.r * 255f).ToString("X2") + Mathf.RoundToInt(c.g * 255f).ToString("X2") + Mathf.RoundToInt(c.b * 255f).ToString("X2");
	}
}
public sealed class ModelData
{
	public Mesh Mesh;

	public string[] MaterialNames;

	public Texture2D[] Textures;

	public Color[] Colors;

	public bool[] Cutout;

	public string Source;

	public int SubMeshCount => (MaterialNames != null) ? MaterialNames.Length : 0;
}
public static class ModelKit
{
	public const string Version = "1.0.1";

	private static readonly Dictionary<string, ModelData> _cache = new Dictionary<string, ModelData>();

	public static void UseLogger(Action<string> info, Action<string> warn)
	{
		Kit.UseLogger(info, warn);
	}

	public static ModelData Load(string objName, AssetSource source)
	{
		return Load(objName, source, null);
	}

	public static ModelData Load(string objName, AssetSource source, TextureOptions textures)
	{
		if (string.IsNullOrEmpty(objName))
		{
			return null;
		}
		if (_cache.TryGetValue(objName, out var value))
		{
			return value;
		}
		ModelData modelData = ObjParser.Load(objName, source, textures);
		_cache[objName] = modelData;
		return modelData;
	}

	public static void Forget(string objName)
	{
		if (objName == null)
		{
			_cache.Clear();
		}
		else
		{
			_cache.Remove(objName);
		}
	}

	public static bool Available(string objName, AssetSource source)
	{
		return source?.Has(objName) ?? false;
	}

	public static GameObject[] Attach(GameObject target, ModelData model, Material template)
	{
		return Attach(target, model, template, calmMaterials: true);
	}

	public static GameObject[] Attach(GameObject target, ModelData model, Material template, bool calmMaterials)
	{
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)target == (Object)null || model == null || (Object)(object)model.Mesh == (Object)null)
		{
			return (GameObject[])(object)new GameObject[0];
		}
		try
		{
			if ((Object)(object)template == (Object)null)
			{
				template = Materials.FindTemplate(target);
			}
			Material[] array = Materials.Build(model, template, calmMaterials);
			if (array.Length == 0)
			{
				return (GameObject[])(object)new GameObject[0];
			}
			GameObject val = new GameObject("ModelKit_" + ((Object)model.Mesh).name);
			val.transform.SetParent(target.transform, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one;
			val.layer = target.layer;
			MeshFilter val2 = val.AddComponent<MeshFilter>();
			val2.sharedMesh = model.Mesh;
			MeshRenderer val3 = val.AddComponent<MeshRenderer>();
			((Renderer)val3).sharedMaterials = array;
			return (GameObject[])(object)new GameObject[1] { val };
		}
		catch (Exception e)
		{
			Kit.Ex("ModelKit.Attach", e);
			return (GameObject[])(object)new GameObject[0];
		}
	}

	public static GameObject[] Replace(GameObject target, string objName, AssetSource source)
	{
		return Replace(target, objName, source, null, calmMaterials: true);
	}

	public static GameObject[] Replace(GameObject target, string objName, AssetSource source, TextureOptions textures, bool calmMaterials)
	{
		if ((Object)(object)target == (Object)null)
		{
			return (GameObject[])(object)new GameObject[0];
		}
		ModelData modelData = Load(objName, source, textures);
		if (modelData == null)
		{
			return (GameObject[])(object)new GameObject[0];
		}
		try
		{
			Material template = Materials.FindTemplate(target);
			GameObject[] array = Attach(target, modelData, template, calmMaterials);
			if (array.Length == 0)
			{
				return array;
			}
			Hide(target, array);
			return array;
		}
		catch (Exception e)
		{
			Kit.Ex("ModelKit.Replace(" + objName + ")", e);
			return (GameObject[])(object)new GameObject[0];
		}
	}

	public static void Hide(GameObject target, GameObject[] keep)
	{
		if ((Object)(object)target == (Object)null)
		{
			return;
		}
		try
		{
			Renderer[] componentsInChildren = target.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				bool flag = false;
				if (keep != null)
				{
					for (int j = 0; j < keep.Length; j++)
					{
						if (flag)
						{
							break;
						}
						if ((Object)(object)keep[j] != (Object)null && ((Component)val).transform.IsChildOf(keep[j].transform))
						{
							flag = true;
						}
					}
				}
				if (!flag)
				{
					val.enabled = false;
				}
			}
		}
		catch (Exception e)
		{
			Kit.Ex("ModelKit.Hide", e);
		}
	}

	public static void Place(GameObject[] parts, float scale, float yaw, float heightOffset)
	{
		//IL_002b: 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_005c: 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)
		if (parts == null)
		{
			return;
		}
		for (int i = 0; i < parts.Length; i++)
		{
			if (!((Object)(object)parts[i] == (Object)null))
			{
				try
				{
					Transform transform = parts[i].transform;
					transform.localScale = Vector3.one * ((!(scale <= 0f)) ? scale : 1f);
					transform.localRotation = Quaternion.Euler(0f, yaw, 0f);
					transform.localPosition = new Vector3(0f, heightOffset, 0f);
				}
				catch (Exception e)
				{
					Kit.Ex("ModelKit.Place", e);
				}
			}
		}
	}

	public static Bounds BoundsOf(GameObject[] parts)
	{
		//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_0019: 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_007e: 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)
		Bounds bounds = default(Bounds);
		((Bounds)(ref bounds))..ctor(Vector3.zero, Vector3.zero);
		bool flag = false;
		if (parts == null)
		{
			return bounds;
		}
		foreach (GameObject val in parts)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					if (!flag)
					{
						bounds = val2.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val2.bounds);
					}
				}
			}
		}
		return bounds;
	}
}
public static class ObjParser
{
	private static readonly char[] Space = new char[2] { ' ', '\t' };

	private static readonly char[] Slashes = new char[2] { '/', '\\' };

	private static float F(string s)
	{
		float result;
		return (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out result)) ? 0f : result;
	}

	private static int Index(string s, int count)
	{
		if (!int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
		{
			return -1;
		}
		if (result > 0)
		{
			return result - 1;
		}
		if (result < 0)
		{
			return count + result;
		}
		return -1;
	}

	public static ModelData Load(string objName, AssetSource source, TextureOptions textures)
	{
		if (source == null)
		{
			Kit.Warn("no asset source was given for '" + objName + "'");
			return null;
		}
		string text = source.ReadText(objName);
		if (text == null)
		{
			Kit.Info("'" + objName + "' was not found in " + source.Describe);
			return null;
		}
		try
		{
			return Parse(text, objName, source, textures ?? TextureOptions.Default);
		}
		catch (Exception e)
		{
			Kit.Ex("ObjParser.Load(" + objName + ")", e);
			return null;
		}
	}

	private static ModelData Parse(string text, string objName, AssetSource source, TextureOptions texOpts)
	{
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Expected O, but got Unknown
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0447: Unknown result type (might be due to invalid IL or missing references)
		//IL_044c: Unknown result type (might be due to invalid IL or missing references)
		List<Vector3> list = new List<Vector3>();
		List<Vector3> list2 = new List<Vector3>();
		List<Vector2> list3 = new List<Vector2>();
		List<Vector3> list4 = new List<Vector3>();
		List<Vector3> list5 = new List<Vector3>();
		List<Vector2> list6 = new List<Vector2>();
		Dictionary<string, int> lookup = new Dictionary<string, int>();
		List<List<int>> list7 = new List<List<int>>();
		List<string> list8 = new List<string>();
		List<int> list9 = null;
		string text2 = null;
		bool missingNormals = false;
		string[] array = text.Split('\n');
		foreach (string text3 in array)
		{
			string text4 = text3.Trim();
			if (text4.Length == 0 || text4[0] == '#')
			{
				continue;
			}
			string[] array2 = text4.Split(Space, StringSplitOptions.RemoveEmptyEntries);
			if (array2.Length == 0)
			{
				continue;
			}
			switch (array2[0])
			{
			case "v":
				if (array2.Length >= 4)
				{
					list.Add(new Vector3(0f - F(array2[1]), F(array2[2]), F(array2[3])));
				}
				break;
			case "vn":
				if (array2.Length >= 4)
				{
					list2.Add(new Vector3(0f - F(array2[1]), F(array2[2]), F(array2[3])));
				}
				break;
			case "vt":
				if (array2.Length >= 3)
				{
					list3.Add(new Vector2(F(array2[1]), F(array2[2])));
				}
				break;
			case "mtllib":
				if (array2.Length >= 2)
				{
					text2 = array2[1];
				}
				break;
			case "usemtl":
			{
				string item = ((array2.Length < 2) ? "default" : array2[1]);
				int num = list8.IndexOf(item);
				if (num >= 0)
				{
					list9 = list7[num];
					break;
				}
				list9 = new List<int>();
				list7.Add(list9);
				list8.Add(item);
				break;
			}
			case "f":
				if (list9 == null)
				{
					list9 = new List<int>();
					list7.Add(list9);
					list8.Add("default");
				}
				AddFace(array2, list, list2, list3, list4, list5, list6, lookup, list9, ref missingNormals);
				break;
			}
		}
		if (list4.Count == 0 || list7.Count == 0)
		{
			Kit.Warn("'" + objName + "' has no faces that can be drawn");
			return null;
		}
		Mesh val = new Mesh();
		((Object)val).name = objName;
		val.indexFormat = (IndexFormat)(list4.Count > 65000);
		val.SetVertices(list4);
		bool flag = !missingNormals && list5.Count == list4.Count;
		if (flag)
		{
			val.SetNormals(list5);
		}
		if (list6.Count == list4.Count)
		{
			val.SetUVs(0, list6);
		}
		List<int> list10 = new List<int>();
		for (int j = 0; j < list7.Count; j++)
		{
			if (list7[j].Count > 0)
			{
				list10.Add(j);
			}
		}
		val.subMeshCount = list10.Count;
		string[] array3 = new string[list10.Count];
		for (int k = 0; k < list10.Count; k++)
		{
			val.SetTriangles(list7[list10[k]], k);
			array3[k] = list8[list10[k]];
		}
		if (!flag)
		{
			val.RecalculateNormals();
		}
		val.RecalculateBounds();
		ModelData modelData = new ModelData();
		modelData.Mesh = val;
		modelData.MaterialNames = array3;
		modelData.Textures = (Texture2D[])(object)new Texture2D[array3.Length];
		modelData.Colors = (Color[])(object)new Color[array3.Length];
		modelData.Cutout = new bool[array3.Length];
		modelData.Source = source.Describe;
		ModelData modelData2 = modelData;
		for (int l = 0; l < array3.Length; l++)
		{
			ref Color reference = ref modelData2.Colors[l];
			reference = Color.white;
		}
		if (text2 != null)
		{
			ApplyMtl(modelData2, text2, objName, source, texOpts);
		}
		Kit.Info("loaded '" + objName + "': " + list4.Count + " vertices, " + val.triangles.Length / 3 + " triangles, " + array3.Length + " material(s), from " + source.Describe + ((!flag) ? " (normals calculated - the file did not supply one for every vertex)" : ""));
		return modelData2;
	}

	private static void AddFace(string[] p, List<Vector3> positions, List<Vector3> normals, List<Vector2> uvs, List<Vector3> outPos, List<Vector3> outNrm, List<Vector2> outUv, Dictionary<string, int> lookup, List<int> tris, ref bool missingNormals)
	{
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		int num = p.Length - 1;
		if (num < 3)
		{
			return;
		}
		int[] array = new int[num];
		for (int i = 0; i < num; i++)
		{
			string text = p[i + 1];
			if (!lookup.TryGetValue(text, out var value))
			{
				string[] array2 = text.Split('/');
				int num2 = Index(array2[0], positions.Count);
				if (num2 < 0 || num2 >= positions.Count)
				{
					return;
				}
				int num3 = ((array2.Length <= 1 || array2[1].Length <= 0) ? (-1) : Index(array2[1], uvs.Count));
				int num4 = ((array2.Length <= 2 || array2[2].Length <= 0) ? (-1) : Index(array2[2], normals.Count));
				outPos.Add(positions[num2]);
				outUv.Add((num3 < 0 || num3 >= uvs.Count) ? Vector2.zero : uvs[num3]);
				if (num4 >= 0 && num4 < normals.Count)
				{
					outNrm.Add(normals[num4]);
				}
				else
				{
					outNrm.Add(Vector3.zero);
					missingNormals = true;
				}
				value = (lookup[text] = outPos.Count - 1);
			}
			array[i] = value;
		}
		for (int j = 1; j < num - 1; j++)
		{
			tris.Add(array[0]);
			tris.Add(array[j + 1]);
			tris.Add(array[j]);
		}
	}

	private static void ApplyMtl(ModelData model, string mtlName, string objName, AssetSource source, TextureOptions texOpts)
	{
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		string text = source.ReadText(mtlName);
		if (text == null)
		{
			Kit.Info("'" + objName + "' names '" + mtlName + "' but it is not there; using plain colours");
			return;
		}
		Dictionary<string, string> dictionary = new Dictionary<string, string>();
		Dictionary<string, Color> dictionary2 = new Dictionary<string, Color>();
		string text2 = null;
		string[] array = text.Split('\n');
		foreach (string text3 in array)
		{
			string text4 = text3.Trim();
			if (text4.Length == 0 || text4[0] == '#')
			{
				continue;
			}
			string[] array2 = text4.Split(Space, StringSplitOptions.RemoveEmptyEntries);
			if (array2.Length < 2)
			{
				continue;
			}
			if (array2[0] == "newmtl")
			{
				text2 = array2[1];
			}
			else
			{
				if (text2 == null)
				{
					continue;
				}
				if (array2[0] == "map_Kd")
				{
					string text5 = array2[^1];
					int num = text5.LastIndexOfAny(Slashes);
					if (num >= 0)
					{
						text5 = text5.Substring(num + 1);
					}
					dictionary[text2] = text5;
				}
				else if (array2[0] == "Kd" && array2.Length >= 4)
				{
					dictionary2[text2] = new Color(F(array2[1]), F(array2[2]), F(array2[3]), 1f);
				}
			}
		}
		Dictionary<string, Texture2D> dictionary3 = new Dictionary<string, Texture2D>();
		for (int j = 0; j < model.MaterialNames.Length; j++)
		{
			string key = model.MaterialNames[j];
			if (dictionary2.TryGetValue(key, out var value))
			{
				model.Colors[j] = value;
			}
			if (!dictionary.TryGetValue(key, out var value2))
			{
				continue;
			}
			if (!dictionary3.TryGetValue(value2, out var value3))
			{
				value3 = TextureLoader.Load(value2, source, texOpts);
				if ((Object)(object)value3 == (Object)null)
				{
					Kit.Warn("the model asks for texture '" + value2 + "' but it could not be loaded - that surface will be drawn as a flat colour.");
				}
				dictionary3[value2] = value3;
			}
			model.Textures[j] = value3;
			if ((Object)(object)value3 != (Object)null)
			{
				model.Cutout[j] = TextureLoader.HasHoles(value3);
			}
		}
	}
}
public sealed class TextureOptions
{
	public bool PointFilter = true;

	public TextureWrapMode Wrap = (TextureWrapMode)0;

	public bool Mipmaps = true;

	public byte CutoutThreshold = 250;

	public static TextureOptions Default => new TextureOptions();
}
public static class TextureLoader
{
	public static Texture2D Load(string relative, AssetSource source, TextureOptions options)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		if (source == null)
		{
			return null;
		}
		options = options ?? TextureOptions.Default;
		byte[] array = source.ReadOrInflate(relative);
		if (array == null)
		{
			return null;
		}
		try
		{
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, options.Mipmaps);
			if (!ImageConversion.LoadImage(val, array))
			{
				Object.Destroy((Object)(object)val);
				Kit.Warn("'" + relative + "' is not an image that can be read");
				return null;
			}
			((Object)val).name = relative;
			((Texture)val).filterMode = (FilterMode)(!options.PointFilter);
			((Texture)val).wrapMode = options.Wrap;
			val.Apply(options.Mipmaps, false);
			return val;
		}
		catch (Exception e)
		{
			Kit.Ex("TextureLoader.Load(" + relative + ")", e);
			return null;
		}
	}

	public static bool HasHoles(Texture2D tex)
	{
		return HasHoles(tex, 250);
	}

	public static bool HasHoles(Texture2D tex, byte threshold)
	{
		if ((Object)(object)tex == (Object)null)
		{
			return false;
		}
		try
		{
			Color32[] pixels = tex.GetPixels32();
			for (int i = 0; i < pixels.Length; i++)
			{
				if (pixels[i].a < threshold)
				{
					return true;
				}
			}
			return false;
		}
		catch
		{
			return false;
		}
	}
}
[BepInPlugin("com.htf.modelkit", "How To Fish - ModelKit", "1.0.1")]
public class ModelKitPlugin : BaseUnityPlugin
{
	public const string Guid = "com.htf.modelkit";

	private void Awake()
	{
		ModelKit.UseLogger(delegate(string m)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)m);
		}, delegate(string m)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)m);
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ModelKit 1.0.1 ready. This is a library: it does nothing on its own.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Mods use it to load OBJ/MTL/PNG models without an AssetBundle, so a game update cannot invalidate their art.");
	}
}