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.");
}
}