Decompiled source of SofaMod v1.3.0

SofaMod.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.Building;
using Il2CppScheduleOne.Core.Items.Framework;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Dialogue;
using Il2CppScheduleOne.EntityFramework;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.ObjectScripts;
using Il2CppScheduleOne.Tiles;
using Il2CppScheduleOne.UI.Shop;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using Microsoft.CodeAnalysis;
using SofaMod;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "SofaMod", "1.3.0", "Nicolassut", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("SofaMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SofaMod")]
[assembly: AssemblyTitle("SofaMod")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SofaMod
{
	internal class FurnitureItemSpec
	{
		public string ID = "";

		public string DisplayName = "";

		public float Price = 800f;

		public string Description = "";

		public string GlbFilename = "";

		public string IconFilename = "";

		public string MeshGOName = "Mesh";

		public float Scale = 0.7125f;

		public Vector3 LocalEuler = Vector3.zero;

		public Mesh? Mesh;

		public List<GlbMaterialInfo> GlbMaterials = new List<GlbMaterialInfo>();

		public Material[]? CachedMaterials;

		public float DonorFloorY;

		public StorableItemDefinition? Definition;
	}
	public class Core : MelonMod
	{
		internal static readonly FurnitureItemSpec Sofa = new FurnitureItemSpec
		{
			ID = "sofa",
			DisplayName = "Sofa",
			Price = 600f,
			Description = "A stylish sofa. Place it in your property.",
			GlbFilename = "vintage_sofa.glb",
			IconFilename = "sofa_icon.png",
			MeshGOName = "SofaMesh"
		};

		internal static readonly FurnitureItemSpec FancySofa = new FurnitureItemSpec
		{
			ID = "fancy_sofa",
			DisplayName = "Fancy Sofa",
			Price = 3000f,
			Description = "A luxurious tartan-upholstered sofa, hand-finished with deep cushions in rich indigo and navy tones. A centrepiece worthy of any refined estate.",
			GlbFilename = "sofa.glb",
			IconFilename = "fancysofa.png",
			MeshGOName = "FancySofaMesh",
			LocalEuler = new Vector3(0f, 90f, 0f),
			Scale = 1.3225f
		};

		internal static readonly HashSet<string> OwnedIDs = new HashSet<string> { "sofa", "fancy_sofa" };

		internal static Registry? RegInstance;

		public override void OnInitializeMelon()
		{
			((MelonBase)this).LoggerInstance.Msg("SofaMod loaded.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (!(sceneName != "Main"))
			{
				if ((Object)(object)RegInstance != (Object)null)
				{
					ReRegister(Sofa);
					ReRegister(FancySofa);
				}
				MelonCoroutines.Start(InjectIntoShops());
			}
		}

		private static void ReRegister(FurnitureItemSpec spec)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			if ((Object)(object)spec.Definition == (Object)null || (Object)(object)RegInstance == (Object)null)
			{
				return;
			}
			try
			{
				RegInstance.AddToRegistry((ItemDefinition)(object)spec.Definition);
			}
			catch
			{
			}
			try
			{
				ItemRegister val = new ItemRegister();
				val.ID = spec.ID;
				val.Definition = ((Il2CppObjectBase)spec.Definition).TryCast<ItemDefinition>();
				RegInstance.AddToItemDictionary(val);
				MelonLogger.Msg("[SofaMod] " + spec.ID + " re-registered for scene.");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[SofaMod] " + spec.ID + " re-registration failed: " + ex.Message);
			}
		}

		private static IEnumerator InjectIntoShops()
		{
			MelonLogger.Msg($"[SofaMod] InjectIntoShops coroutine started (cap {20} x {1.5f:F1}s).");
			int totalSofa = 0;
			int totalFancy = 0;
			int attempt = 0;
			yield return null;
			while (attempt < 20)
			{
				attempt++;
				bool usedFallback;
				ShopInterface[] allShops = GetAllShops(out usedFallback);
				int num = ((allShops != null) ? allShops.Length : 0);
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				StringBuilder stringBuilder = new StringBuilder();
				if (allShops != null)
				{
					for (int i = 0; i < allShops.Length; i++)
					{
						ShopInterface val = allShops[i];
						if ((Object)(object)val == (Object)null)
						{
							continue;
						}
						GameObject gameObject = ((Component)val).gameObject;
						string text = ((gameObject != null) ? ((Object)gameObject).name : null) ?? "?";
						if (i > 0)
						{
							stringBuilder.Append(", ");
						}
						stringBuilder.Append(text);
						if (text.IndexOf("hardware", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							num2++;
						}
						if (text.IndexOf("boutique", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("bleuball", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							num3++;
						}
						if (val.Listings == null)
						{
							continue;
						}
						for (int j = 0; j < val.Listings.Count; j++)
						{
							ShopListing obj = val.Listings[j];
							object obj2;
							if (obj == null)
							{
								obj2 = null;
							}
							else
							{
								StorableItemDefinition item = obj.Item;
								obj2 = ((item != null) ? ((BaseItemDefinition)item).ID : null);
							}
							if ((string?)obj2 == "bed")
							{
								num4++;
								break;
							}
						}
					}
				}
				if (num == 0)
				{
					if (attempt == 1 || attempt % 5 == 0 || attempt == 20)
					{
						MelonLogger.Msg($"[SofaMod] Attempt {attempt}/{20}: source={(usedFallback ? "FindObjectsOfType" : "AllShops")} returned 0 shop(s) (likely client-side network sync); retrying in {1.5f:F1}s.");
					}
					yield return (object)new WaitForSeconds(1.5f);
					continue;
				}
				int num5 = 0;
				int num6 = 0;
				ShopInterface[] array = allShops;
				foreach (ShopInterface val2 in array)
				{
					if ((Object)(object)val2 == (Object)null || val2.Listings == null)
					{
						continue;
					}
					GameObject gameObject2 = ((Component)val2).gameObject;
					string text2 = ((gameObject2 != null) ? ((Object)gameObject2).name : null) ?? "?";
					string shopName = "";
					try
					{
						shopName = val2.ShopName ?? "";
					}
					catch
					{
					}
					bool flag = false;
					bool flag2 = false;
					bool flag3 = false;
					for (int l = 0; l < val2.Listings.Count; l++)
					{
						ShopListing obj4 = val2.Listings[l];
						object obj5;
						if (obj4 == null)
						{
							obj5 = null;
						}
						else
						{
							StorableItemDefinition item2 = obj4.Item;
							obj5 = ((item2 != null) ? ((BaseItemDefinition)item2).ID : null);
						}
						if ((string?)obj5 == "bed")
						{
							flag = true;
						}
						if ((string?)obj5 == "sofa")
						{
							flag2 = true;
						}
						if ((string?)obj5 == "fancy_sofa")
						{
							flag3 = true;
						}
					}
					bool flag4 = text2.IndexOf("hardware", StringComparison.OrdinalIgnoreCase) >= 0;
					if (flag && !flag2 && flag4 && (Object)(object)Sofa.Definition != (Object)null && AppendListing(val2, Sofa.Definition, Sofa.ID, Sofa.Price))
					{
						num5++;
					}
					if (!flag3 && (Object)(object)FancySofa.Definition != (Object)null && LooksLikeFancyFurnitureStore(text2, shopName) && AppendListing(val2, FancySofa.Definition, FancySofa.ID, FancySofa.Price))
					{
						num6++;
					}
				}
				totalSofa += num5;
				totalFancy += num6;
				bool num7 = totalSofa > 0 && totalFancy > 0;
				if (!num7 && (attempt == 1 || attempt % 5 == 0 || attempt == 20))
				{
					MelonLogger.Msg($"[SofaMod] Attempt {attempt}/{20}: source={(usedFallback ? "FindObjectsOfType" : "AllShops")} shops={num} (hardware={num2}, boutique={num3}, bedSellers={num4}) injected_this_pass(sofa={num5}, fancy={num6}); shops=[{stringBuilder}]");
				}
				if (num7)
				{
					MelonLogger.Msg($"[SofaMod] Shop injection complete: Sofa into {totalSofa} shop(s), Fancy Sofa into {totalFancy} shop(s) (attempt {attempt}/{20}, source={(usedFallback ? "FindObjectsOfType" : "AllShops")}).");
					yield break;
				}
				yield return (object)new WaitForSeconds(1.5f);
			}
			MelonLogger.Warning($"[SofaMod] Shop injection gave up after {20} attempts (~{30f:F0}s). Final: Sofa into {totalSofa} shop(s), Fancy Sofa into {totalFancy} shop(s). Possible causes: " + "MP client never received scene replication, network was unusually slow, or the donor (bed) / boutique is missing from the scene. Check the per-attempt diagnostic lines above for shop discovery state.");
		}

		private static ShopInterface[] GetAllShops(out bool usedFallback)
		{
			usedFallback = false;
			try
			{
				List<ShopInterface> allShops = ShopInterface.AllShops;
				if (allShops != null && allShops.Count > 0)
				{
					ShopInterface[] array = (ShopInterface[])(object)new ShopInterface[allShops.Count];
					for (int i = 0; i < allShops.Count; i++)
					{
						array[i] = allShops[i];
					}
					return array;
				}
			}
			catch
			{
			}
			usedFallback = true;
			return Il2CppArrayBase<ShopInterface>.op_Implicit(Object.FindObjectsOfType<ShopInterface>());
		}

		private static bool AppendListing(ShopInterface shop, StorableItemDefinition def, string id, float price)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			try
			{
				ShopListing val = new ShopListing();
				val.Item = def;
				val.name = id;
				val.OverridePrice = true;
				val.OverriddenPrice = price;
				val.CurrentStock = 999;
				val.CanBeDelivered = false;
				shop.Listings.Add(val);
				shop.CreateListingUI(val);
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(39, 3);
				defaultInterpolatedStringHandler.AppendLiteral("[SofaMod] ");
				defaultInterpolatedStringHandler.AppendFormatted(id);
				defaultInterpolatedStringHandler.AppendLiteral(" appended to ");
				GameObject gameObject = ((Component)shop).gameObject;
				defaultInterpolatedStringHandler.AppendFormatted(((gameObject != null) ? ((Object)gameObject).name : null) ?? "?");
				defaultInterpolatedStringHandler.AppendLiteral(" ");
				defaultInterpolatedStringHandler.AppendLiteral("(now ");
				defaultInterpolatedStringHandler.AppendFormatted(shop.Listings.Count);
				defaultInterpolatedStringHandler.AppendLiteral(" listings)");
				MelonLogger.Msg(defaultInterpolatedStringHandler.ToStringAndClear());
				return true;
			}
			catch (Exception ex)
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(29, 3);
				defaultInterpolatedStringHandler.AppendLiteral("[SofaMod] ");
				defaultInterpolatedStringHandler.AppendFormatted(id);
				defaultInterpolatedStringHandler.AppendLiteral(" inject failed (");
				GameObject gameObject2 = ((Component)shop).gameObject;
				defaultInterpolatedStringHandler.AppendFormatted(((gameObject2 != null) ? ((Object)gameObject2).name : null) ?? "?");
				defaultInterpolatedStringHandler.AppendLiteral("): ");
				defaultInterpolatedStringHandler.AppendFormatted(ex.Message);
				MelonLogger.Error(defaultInterpolatedStringHandler.ToStringAndClear());
				return false;
			}
		}

		private static bool LooksLikeFancyFurnitureStore(string goName, string shopName)
		{
			string text = (goName ?? "").ToLowerInvariant();
			string text2 = (shopName ?? "").ToLowerInvariant();
			if (!text.Contains("boutique") && !text2.Contains("boutique") && !text.Contains("bleuball"))
			{
				return text2.Contains("bleuball");
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Registry), "Start")]
	public static class Registry_Start_Patch
	{
		private static void Postfix(Registry __instance)
		{
			try
			{
				List<ItemRegister> itemRegistry = __instance.ItemRegistry;
				if (itemRegistry == null)
				{
					MelonLogger.Error("[SofaMod] ItemRegistry is null");
					return;
				}
				BuildableItemDefinition val = null;
				for (int i = 0; i < itemRegistry.Count; i++)
				{
					ItemRegister val2 = itemRegistry[i];
					if (val2 == null || val2.ID != "bed")
					{
						continue;
					}
					val = ((Il2CppObjectBase)val2).TryCast<BuildableItemDefinition>();
					if ((Object)(object)val == (Object)null)
					{
						try
						{
							ItemDefinition definition = val2.Definition;
							val = ((definition != null) ? ((Il2CppObjectBase)definition).TryCast<BuildableItemDefinition>() : null);
						}
						catch
						{
						}
					}
					break;
				}
				if ((Object)(object)((val != null) ? val.BuiltItem : null) == (Object)null)
				{
					MelonLogger.Error("[SofaMod] Bed not found — cannot create furniture templates.");
					return;
				}
				MelonLogger.Msg("[SofaMod] Using 'bed' as BuiltItem FishNet base (3×5 footprint).");
				RegisterFurniture(__instance, val, Core.Sofa);
				RegisterFurniture(__instance, val, Core.FancySofa);
				Core.RegInstance = __instance;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[SofaMod] Registry patch failed: " + ex);
			}
		}

		private static void RegisterFurniture(Registry registry, BuildableItemDefinition bedDef, FurnitureItemSpec spec)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			try
			{
				BuildableItemDefinition val = Object.Instantiate<BuildableItemDefinition>(bedDef);
				((Object)val).name = spec.DisplayName;
				((BaseItemDefinition)val).ID = spec.ID;
				((BaseItemDefinition)val).Name = spec.DisplayName;
				((StorableItemDefinition)val).BasePurchasePrice = spec.Price;
				BaseItemDefinition val2 = ((Il2CppObjectBase)val).TryCast<BaseItemDefinition>();
				if ((Object)(object)val2 != (Object)null)
				{
					val2.Description = spec.Description;
				}
				StorableItemDefinition val3 = ((Il2CppObjectBase)val).TryCast<StorableItemDefinition>();
				if ((Object)(object)val3 != (Object)null)
				{
					val3.StoredItem = null;
				}
				LoadIcon(spec, val2);
				if ((Object)(object)spec.Mesh == (Object)null)
				{
					LoadAssetsForSpec(bedDef, spec);
				}
				val.BuiltItem = bedDef.BuiltItem;
				registry.AddToRegistry((ItemDefinition)(object)val);
				try
				{
					ItemRegister val4 = new ItemRegister();
					val4.ID = spec.ID;
					val4.Definition = ((Il2CppObjectBase)val).TryCast<ItemDefinition>();
					registry.AddToItemDictionary(val4);
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("[SofaMod] " + spec.ID + " AddToItemDictionary failed (non-fatal): " + ex.Message);
				}
				spec.Definition = ((Il2CppObjectBase)val).TryCast<StorableItemDefinition>();
				MelonLogger.Msg("[SofaMod] " + spec.ID + " registered.");
			}
			catch (Exception ex2)
			{
				MelonLogger.Error("[SofaMod] " + spec.ID + " registration failed: " + ex2);
			}
		}

		private static void LoadIcon(FurnitureItemSpec spec, BaseItemDefinition? asBase)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			try
			{
				string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), spec.IconFilename);
				if (!File.Exists(path))
				{
					MelonLogger.Warning("[SofaMod] " + spec.ID + " icon not found: " + spec.IconFilename);
					return;
				}
				byte[] array = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2);
				ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array));
				float num = 0.04f;
				float num2 = (float)((Texture)val).width * num;
				float num3 = (float)((Texture)val).height * num;
				float num4 = (float)((Texture)val).width * (1f - 2f * num);
				float num5 = (float)((Texture)val).height * (1f - 2f * num);
				Sprite icon = Sprite.Create(val, new Rect(num2, num3, num4, num5), new Vector2(0.5f, 0.5f));
				if ((Object)(object)asBase != (Object)null)
				{
					asBase.Icon = icon;
				}
				MelonLogger.Msg("[SofaMod] " + spec.ID + " icon loaded: " + spec.IconFilename);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[SofaMod] " + spec.ID + " icon load failed: " + ex.Message);
			}
		}

		private static void LoadAssetsForSpec(BuildableItemDefinition bedDef, FurnitureItemSpec spec)
		{
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Expected O, but got Unknown
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_042c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Expected O, but got Unknown
			//IL_0439: 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_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: 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_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			GlbLoadResult glbLoadResult = GlbLoader.Load(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), spec.GlbFilename));
			spec.Mesh = glbLoadResult.Mesh;
			spec.GlbMaterials = glbLoadResult.Materials ?? new List<GlbMaterialInfo>();
			if ((Object)(object)spec.Mesh != (Object)null)
			{
				MelonLogger.Msg($"[SofaMod] {spec.ID} GLB loaded — {spec.Mesh.vertexCount} verts, {spec.GlbMaterials.Count} material(s).");
			}
			float num = 0f;
			try
			{
				GameObject gameObject = ((Component)bedDef.BuiltItem).gameObject;
				foreach (MeshRenderer componentsInChild in gameObject.GetComponentsInChildren<MeshRenderer>(true))
				{
					MeshFilter val = ((componentsInChild != null) ? ((Component)componentsInChild).GetComponent<MeshFilter>() : null);
					if (!((Object)(object)((val != null) ? val.sharedMesh : null) == (Object)null))
					{
						Bounds bounds = val.sharedMesh.bounds;
						Vector3 val2 = ((Component)componentsInChild).transform.TransformPoint(new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).center.z));
						Vector3 val3 = gameObject.transform.InverseTransformPoint(val2);
						if (val3.y < num)
						{
							num = val3.y;
						}
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[SofaMod] " + spec.ID + " donor floor scan failed: " + ex.Message);
			}
			spec.DonorFloorY = num;
			MelonLogger.Msg($"[SofaMod] {spec.ID} donor floor reference Y = {num:F4}");
			Shader val4 = Shader.Find("Universal Render Pipeline/Lit");
			if ((Object)(object)val4 == (Object)null)
			{
				MelonLogger.Warning("[SofaMod] " + spec.ID + ": URP Lit shader not found — using Unity default materials.");
				spec.CachedMaterials = null;
				return;
			}
			if (spec.GlbMaterials.Count == 0)
			{
				MelonLogger.Warning("[SofaMod] " + spec.ID + ": no GLB materials.");
				spec.CachedMaterials = null;
				return;
			}
			Material[] array = (Material[])(object)new Material[spec.GlbMaterials.Count];
			for (int i = 0; i < spec.GlbMaterials.Count; i++)
			{
				GlbMaterialInfo glbMaterialInfo = spec.GlbMaterials[i];
				Material val5 = new Material(val4);
				val5.SetFloat("_Metallic", 0f);
				val5.SetFloat("_Smoothness", 0.15f);
				if ((Object)(object)glbMaterialInfo.BaseColorTexture != (Object)null)
				{
					val5.SetTexture("_BaseMap", (Texture)(object)glbMaterialInfo.BaseColorTexture);
					val5.SetTexture("_MainTex", (Texture)(object)glbMaterialInfo.BaseColorTexture);
				}
				Color baseColorFactor = glbMaterialInfo.BaseColorFactor;
				Color val6 = ((baseColorFactor.r > 0.95f && baseColorFactor.g > 0.95f && baseColorFactor.b > 0.95f) ? Color.white : baseColorFactor);
				if ((Object)(object)glbMaterialInfo.BaseColorTexture == (Object)null && val6 == Color.white)
				{
					((Color)(ref val6))..ctor(0.72f, 0.58f, 0.44f, 1f);
				}
				val5.SetColor("_BaseColor", val6);
				val5.SetColor("_Color", val6);
				val5.color = val6;
				Object.DontDestroyOnLoad((Object)(object)val5);
				array[i] = val5;
			}
			spec.CachedMaterials = array;
			MelonLogger.Msg($"[SofaMod] {spec.ID} assets loaded ({array.Length} cached material(s)).");
			try
			{
				GameObject val7 = new GameObject("SofaMod_AssetHolder_" + spec.ID);
				val7.SetActive(false);
				Object.DontDestroyOnLoad((Object)val7);
				val7.AddComponent<MeshFilter>().sharedMesh = spec.Mesh;
				MeshRenderer val8 = val7.AddComponent<MeshRenderer>();
				if (spec.CachedMaterials != null && spec.CachedMaterials.Length != 0)
				{
					((Renderer)val8).sharedMaterials = Il2CppReferenceArray<Material>.op_Implicit(spec.CachedMaterials);
				}
				MelonLogger.Msg("[SofaMod] " + spec.ID + " asset holder created (DontDestroyOnLoad).");
			}
			catch (Exception ex2)
			{
				MelonLogger.Warning("[SofaMod] " + spec.ID + " asset holder creation failed: " + ex2.Message);
			}
		}
	}
	internal static class SofaVisuals
	{
		public static void Apply(GameObject? target, FurnitureItemSpec spec)
		{
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: 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_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: 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_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null || (Object)(object)spec.Mesh == (Object)null)
			{
				MelonLogger.Warning($"[SofaMod] {spec.ID} Apply skipped: target={(((Object)(object)target == (Object)null) ? "null" : ((Object)target).name)}, mesh={(((Object)(object)spec.Mesh == (Object)null) ? "null" : "ok")}");
			}
			else
			{
				if ((Object)(object)target.transform.Find(spec.MeshGOName) != (Object)null)
				{
					return;
				}
				try
				{
					foreach (MeshRenderer componentsInChild in target.GetComponentsInChildren<MeshRenderer>(true))
					{
						if ((Object)(object)componentsInChild != (Object)null)
						{
							((Renderer)componentsInChild).enabled = false;
						}
					}
					foreach (SkinnedMeshRenderer componentsInChild2 in target.GetComponentsInChildren<SkinnedMeshRenderer>(true))
					{
						if ((Object)(object)componentsInChild2 != (Object)null)
						{
							((Renderer)componentsInChild2).enabled = false;
						}
					}
					foreach (Light componentsInChild3 in target.GetComponentsInChildren<Light>(true))
					{
						if ((Object)(object)componentsInChild3 != (Object)null)
						{
							((Behaviour)componentsInChild3).enabled = false;
						}
					}
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("[SofaMod] Renderer disable threw: " + ex.Message);
				}
				try
				{
					Il2CppArrayBase<FootprintTile> componentsInChildren = target.GetComponentsInChildren<FootprintTile>(true);
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						if ((Object)(object)componentsInChildren[i] != (Object)null)
						{
							componentsInChildren[i].RequiredOffset = 0f;
						}
					}
				}
				catch
				{
				}
				float scale = spec.Scale;
				Quaternion val = Quaternion.Euler(spec.LocalEuler);
				Bounds bounds = spec.Mesh.bounds;
				Vector3 min = ((Bounds)(ref bounds)).min;
				Vector3 max = ((Bounds)(ref bounds)).max;
				Vector3[] array = (Vector3[])(object)new Vector3[8]
				{
					val * new Vector3(min.x, min.y, min.z),
					val * new Vector3(max.x, min.y, min.z),
					val * new Vector3(min.x, max.y, min.z),
					val * new Vector3(max.x, max.y, min.z),
					val * new Vector3(min.x, min.y, max.z),
					val * new Vector3(max.x, min.y, max.z),
					val * new Vector3(min.x, max.y, max.z),
					val * new Vector3(max.x, max.y, max.z)
				};
				Vector3 val2 = array[0];
				Vector3 val3 = array[0];
				for (int j = 1; j < array.Length; j++)
				{
					val2 = Vector3.Min(val2, array[j]);
					val3 = Vector3.Max(val3, array[j]);
				}
				Vector3 val4 = (val2 + val3) * 0.5f;
				GameObject val5 = new GameObject(spec.MeshGOName);
				val5.transform.SetParent(target.transform, false);
				val5.transform.localScale = new Vector3(scale, scale, scale);
				val5.transform.localRotation = val;
				val5.transform.localPosition = new Vector3((0f - val4.x) * scale, spec.DonorFloorY - val2.y * scale, (0f - val4.z) * scale);
				val5.AddComponent<MeshFilter>().sharedMesh = spec.Mesh;
				MeshRenderer val6 = val5.AddComponent<MeshRenderer>();
				if (spec.CachedMaterials != null && spec.CachedMaterials.Length != 0)
				{
					((Renderer)val6).sharedMaterials = Il2CppReferenceArray<Material>.op_Implicit(spec.CachedMaterials);
				}
			}
		}

		public static FurnitureItemSpec? SpecForID(string? id)
		{
			if (id == null)
			{
				return null;
			}
			if (id == Core.Sofa.ID)
			{
				return Core.Sofa;
			}
			if (id == Core.FancySofa.ID)
			{
				return Core.FancySofa;
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(BuildStart_Grid), "StartBuilding")]
	public static class BuildStart_Grid_StartBuilding_Patch
	{
		private static void Postfix(BuildStart_Grid __instance, ItemInstance itemInstance)
		{
			try
			{
				object obj;
				if (itemInstance == null)
				{
					obj = null;
				}
				else
				{
					ItemDefinition definition = itemInstance.Definition;
					obj = ((definition != null) ? ((BaseItemDefinition)definition).ID : null);
				}
				string text = (string)obj;
				FurnitureItemSpec furnitureItemSpec = SofaVisuals.SpecForID(text);
				if (furnitureItemSpec == null)
				{
					return;
				}
				GridItem ghostModelClass = __instance.ghostModelClass;
				if ((Object)(object)ghostModelClass == (Object)null)
				{
					MelonLogger.Warning("[SofaMod] StartBuilding(" + text + "): ghostModelClass is NULL.");
					return;
				}
				SofaVisuals.Apply(((Component)ghostModelClass).gameObject, furnitureItemSpec);
				if (!((Component)ghostModelClass).gameObject.activeSelf)
				{
					((Component)ghostModelClass).gameObject.SetActive(true);
				}
				BuildManager instance = NetworkSingleton<BuildManager>.Instance;
				if (!((Object)(object)instance != (Object)null) || !((Object)(object)instance.ghostMaterial_White != (Object)null))
				{
					return;
				}
				instance.ApplyMaterial(((Component)ghostModelClass).gameObject, instance.ghostMaterial_White, true);
				try
				{
					ghostModelClass.CalculateFootprintTileIntersections();
					ghostModelClass.SetFootprintTileVisiblity(true);
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("[SofaMod] Footprint calc failed: " + ex.Message);
				}
			}
			catch (Exception ex2)
			{
				MelonLogger.Warning("[SofaMod] StartBuilding Postfix error: " + ex2.Message);
			}
		}
	}
	[HarmonyPatch(typeof(GridItem), "SetFootprintTileVisiblity")]
	public static class GridItem_SetFootprintTileVisiblity_Patch
	{
		private static Exception? Finalizer(Exception? __exception)
		{
			if (__exception != null)
			{
				MelonLogger.Warning("[SofaMod] SetFootprintTileVisiblity suppressed: " + __exception.GetType().Name);
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(BuildManager), "StopBuilding")]
	public static class BuildManager_StopBuilding_Patch
	{
		private static Exception? Finalizer(Exception? __exception)
		{
			if (__exception != null)
			{
				MelonLogger.Warning("[SofaMod] StopBuilding exception suppressed: " + __exception.GetType().Name + ": " + __exception.Message);
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(ShopInterface), "HandoverItems")]
	public static class ShopInterface_HandoverItems_Patch
	{
		private static Exception? Finalizer(Exception? __exception)
		{
			if (__exception != null)
			{
				MelonLogger.Error("[SofaMod] HandoverItems threw " + __exception.GetType().Name + ": " + __exception.Message);
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(DialogueController_Dan), "ModifyDialogueText")]
	public static class DialogueController_Dan_Patch
	{
		private static Exception? Finalizer(string dialogueText, ref string __result, Exception? __exception)
		{
			if (__exception != null)
			{
				__result = dialogueText ?? "";
				MelonLogger.Warning("[SofaMod] ModifyDialogueText threw (" + __exception.GetType().Name + "); falling back to unmodified text.");
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(PlaceableStorageEntity), "InitializeGridItem")]
	public static class PlaceableStorageEntity_InitializeGridItem_Patch
	{
		private static void Postfix(PlaceableStorageEntity __instance, ItemInstance instance)
		{
			try
			{
				object id;
				if (instance == null)
				{
					id = null;
				}
				else
				{
					ItemDefinition definition = instance.Definition;
					id = ((definition != null) ? ((BaseItemDefinition)definition).ID : null);
				}
				FurnitureItemSpec furnitureItemSpec = SofaVisuals.SpecForID((string?)id);
				if (furnitureItemSpec != null)
				{
					SofaVisuals.Apply((__instance != null) ? ((Component)__instance).gameObject : null, furnitureItemSpec);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[SofaMod] PSE.InitializeGridItem Postfix failed: " + ex.Message);
			}
		}
	}
	internal struct GlbMaterialInfo
	{
		public Texture2D? BaseColorTexture;

		public Color BaseColorFactor;

		public string Name;
	}
	internal struct GlbLoadResult
	{
		public Mesh? Mesh;

		public List<GlbMaterialInfo> Materials;
	}
	internal static class GlbLoader
	{
		internal static GlbLoadResult Load(string path)
		{
			if (!File.Exists(path))
			{
				MelonLogger.Warning("[SofaMod] GLB not found: " + path);
				return default(GlbLoadResult);
			}
			try
			{
				return Parse(File.ReadAllBytes(path));
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[SofaMod] GLB parse failed: " + ex);
				return default(GlbLoadResult);
			}
		}

		private static GlbLoadResult Parse(byte[] data)
		{
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: 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_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_058f: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fb: Unknown result type (might be due to invalid IL or missing references)
			if (BitConverter.ToUInt32(data, 0) != 1179937895)
			{
				throw new InvalidDataException("Not a GLB file");
			}
			int num = (int)BitConverter.ToUInt32(data, 12);
			string @string = Encoding.UTF8.GetString(data, 20, num);
			int binStart = 20 + num + 8;
			List<Vector3> list = new List<Vector3>();
			List<Vector3> list2 = new List<Vector3>();
			List<Vector2> list3 = new List<Vector2>();
			Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
			int baseVert = 0;
			List<GlbMaterialInfo> list4 = new List<GlbMaterialInfo>();
			using JsonDocument jsonDocument = JsonDocument.Parse(@string);
			JsonElement rootElement = jsonDocument.RootElement;
			JsonElement property = rootElement.GetProperty("accessors");
			JsonElement property2 = rootElement.GetProperty("bufferViews");
			JsonElement property3 = rootElement.GetProperty("meshes");
			JsonElement property4 = rootElement.GetProperty("nodes");
			JsonElement value;
			int index = (rootElement.TryGetProperty("scene", out value) ? value.GetInt32() : 0);
			foreach (int item in from e in rootElement.GetProperty("scenes")[index].GetProperty("nodes").EnumerateArray()
				select e.GetInt32())
			{
				TraverseNode(data, binStart, property4, property3, property, property2, item, Matrix4x4.identity, list, list2, list3, dictionary, ref baseVert);
			}
			foreach (List<int> value4 in dictionary.Values)
			{
				for (int i = 0; i < value4.Count; i += 3)
				{
					int value2 = value4[i + 1];
					value4[i + 1] = value4[i + 2];
					value4[i + 2] = value2;
				}
			}
			List<int> list5 = dictionary.Keys.OrderBy((int k) => k).ToList();
			Mesh val = new Mesh();
			val.indexFormat = (IndexFormat)1;
			val.vertices = Il2CppStructArray<Vector3>.op_Implicit(list.ToArray());
			val.normals = Il2CppStructArray<Vector3>.op_Implicit(list2.ToArray());
			if (list3.Count == list.Count)
			{
				val.uv = Il2CppStructArray<Vector2>.op_Implicit(list3.ToArray());
			}
			val.subMeshCount = list5.Count;
			int num2 = 0;
			for (int j = 0; j < list5.Count; j++)
			{
				int num3 = list5[j];
				int[] array = dictionary[num3].ToArray();
				val.SetTriangles(Il2CppStructArray<int>.op_Implicit(array), j);
				list4.Add(ExtractMaterialAt(rootElement, data, binStart, num3));
				num2 += array.Length / 3;
			}
			val.RecalculateBounds();
			Bounds bounds = val.bounds;
			MelonLogger.Msg($"[SofaMod] GLB loaded — {list.Count} verts, {num2} tris, {list5.Count} submesh(es)/material(s), size {((Bounds)(ref bounds)).size.x:F3}×{((Bounds)(ref bounds)).size.y:F3}×{((Bounds)(ref bounds)).size.z:F3}, center ({((Bounds)(ref bounds)).center.x:F3},{((Bounds)(ref bounds)).center.y:F3},{((Bounds)(ref bounds)).center.z:F3}), min ({((Bounds)(ref bounds)).min.x:F3},{((Bounds)(ref bounds)).min.y:F3},{((Bounds)(ref bounds)).min.z:F3})");
			for (int l = 0; l < list4.Count; l++)
			{
				GlbMaterialInfo glbMaterialInfo = list4[l];
				string value3 = (((Object)(object)glbMaterialInfo.BaseColorTexture != (Object)null) ? $"{((Texture)glbMaterialInfo.BaseColorTexture).width}×{((Texture)glbMaterialInfo.BaseColorTexture).height}" : "no texture");
				MelonLogger.Msg($"[SofaMod]   submesh[{l}] '{glbMaterialInfo.Name}' tex={value3} factor=({glbMaterialInfo.BaseColorFactor.r:F2},{glbMaterialInfo.BaseColorFactor.g:F2},{glbMaterialInfo.BaseColorFactor.b:F2},{glbMaterialInfo.BaseColorFactor.a:F2})");
			}
			GlbLoadResult result = default(GlbLoadResult);
			result.Mesh = val;
			result.Materials = list4;
			return result;
		}

		private static void TraverseNode(byte[] data, int binStart, JsonElement nodes, JsonElement meshes, JsonElement accessors, JsonElement bufferViews, int nodeIdx, Matrix4x4 parentTransform, List<Vector3> allVerts, List<Vector3> allNorms, List<Vector2> allUVs, Dictionary<int, List<int>> trisByMaterial, ref int baseVert)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: 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_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_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: 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_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			JsonElement node = nodes[nodeIdx];
			Matrix4x4 val = GltfNodeMatrix(node);
			Matrix4x4 parentTransform2 = parentTransform * val;
			if (node.TryGetProperty("mesh", out var value))
			{
				JsonElement property = meshes[value.GetInt32()].GetProperty("primitives");
				for (int i = 0; i < property.GetArrayLength(); i++)
				{
					JsonElement jsonElement = property[i];
					JsonElement property2 = jsonElement.GetProperty("attributes");
					Vector3[] array = ReadVec3(data, binStart, accessors[property2.GetProperty("POSITION").GetInt32()], bufferViews);
					Vector3[] array2 = null;
					if (property2.TryGetProperty("NORMAL", out var value2))
					{
						array2 = ReadVec3(data, binStart, accessors[value2.GetInt32()], bufferViews);
					}
					Vector2[] array3 = null;
					if (property2.TryGetProperty("TEXCOORD_0", out var value3))
					{
						array3 = ReadVec2(data, binStart, accessors[value3.GetInt32()], bufferViews);
					}
					int[] array4 = ReadIndices(data, binStart, accessors[jsonElement.GetProperty("indices").GetInt32()], bufferViews);
					for (int j = 0; j < array.Length; j++)
					{
						Vector3 val2 = ((Matrix4x4)(ref parentTransform2)).MultiplyPoint3x4(array[j]);
						array[j] = new Vector3(0f - val2.x, val2.y, val2.z);
					}
					if (array2 != null)
					{
						for (int k = 0; k < array2.Length; k++)
						{
							Vector3 val3 = ((Matrix4x4)(ref parentTransform2)).MultiplyVector(array2[k]);
							array2[k] = new Vector3(0f - val3.x, val3.y, val3.z);
						}
					}
					JsonElement value4;
					int key = (jsonElement.TryGetProperty("material", out value4) ? value4.GetInt32() : (-1));
					if (!trisByMaterial.TryGetValue(key, out List<int> value5))
					{
						value5 = (trisByMaterial[key] = new List<int>());
					}
					allVerts.AddRange(array);
					allNorms.AddRange((IEnumerable<Vector3>)(((object)array2) ?? ((object)new Vector3[array.Length])));
					allUVs.AddRange((IEnumerable<Vector2>)(((object)array3) ?? ((object)new Vector2[array.Length])));
					for (int l = 0; l < array4.Length; l++)
					{
						value5.Add(array4[l] + baseVert);
					}
					baseVert += array.Length;
				}
			}
			if (!node.TryGetProperty("children", out var value6))
			{
				return;
			}
			foreach (JsonElement item in value6.EnumerateArray())
			{
				TraverseNode(data, binStart, nodes, meshes, accessors, bufferViews, item.GetInt32(), parentTransform2, allVerts, allNorms, allUVs, trisByMaterial, ref baseVert);
			}
		}

		private static GlbMaterialInfo ExtractMaterialAt(JsonElement root, byte[] data, int binStart, int matIdx)
		{
			//IL_000a: 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_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Expected O, but got Unknown
			GlbMaterialInfo glbMaterialInfo = default(GlbMaterialInfo);
			glbMaterialInfo.BaseColorFactor = Color.white;
			glbMaterialInfo.Name = ((matIdx < 0) ? "default" : $"mat{matIdx}");
			glbMaterialInfo.BaseColorTexture = null;
			GlbMaterialInfo result = glbMaterialInfo;
			try
			{
				if (matIdx < 0)
				{
					return result;
				}
				if (!root.TryGetProperty("materials", out var value) || matIdx >= value.GetArrayLength())
				{
					return result;
				}
				JsonElement jsonElement = value[matIdx];
				if (jsonElement.TryGetProperty("name", out var value2))
				{
					result.Name = value2.GetString() ?? result.Name;
				}
				if (!jsonElement.TryGetProperty("pbrMetallicRoughness", out var value3))
				{
					return result;
				}
				if (value3.TryGetProperty("baseColorFactor", out var value4))
				{
					float[] array = (from e in value4.EnumerateArray()
						select e.GetSingle()).ToArray();
					result.BaseColorFactor = (Color)((array.Length >= 4) ? new Color(array[0], array[1], array[2], array[3]) : ((array.Length >= 3) ? new Color(array[0], array[1], array[2]) : Color.white));
				}
				if (!value3.TryGetProperty("baseColorTexture", out var value5))
				{
					return result;
				}
				int @int = value5.GetProperty("index").GetInt32();
				if (!root.TryGetProperty("textures", out var value6) || @int >= value6.GetArrayLength())
				{
					return result;
				}
				if (!value6[@int].TryGetProperty("source", out var value7))
				{
					return result;
				}
				int int2 = value7.GetInt32();
				if (!root.TryGetProperty("images", out var value8) || int2 >= value8.GetArrayLength())
				{
					return result;
				}
				if (!value8[int2].TryGetProperty("bufferView", out var value9))
				{
					return result;
				}
				if (!root.TryGetProperty("bufferViews", out var value10))
				{
					return result;
				}
				JsonElement jsonElement2 = value10[value9.GetInt32()];
				JsonElement value11;
				int num = (jsonElement2.TryGetProperty("byteOffset", out value11) ? value11.GetInt32() : 0);
				int int3 = jsonElement2.GetProperty("byteLength").GetInt32();
				byte[] array2 = new byte[int3];
				Array.Copy(data, binStart + num, array2, 0, int3);
				Texture2D val = new Texture2D(2, 2);
				ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array2));
				result.BaseColorTexture = val;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning($"[SofaMod] GLB material[{matIdx}] extraction failed: " + ex.Message);
			}
			return result;
		}

		private static Matrix4x4 GltfNodeMatrix(JsonElement node)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			if (node.TryGetProperty("matrix", out var value))
			{
				float[] array = (from e in value.EnumerateArray()
					select e.GetSingle()).ToArray();
				Matrix4x4 result = default(Matrix4x4);
				((Matrix4x4)(ref result))[0, 0] = array[0];
				((Matrix4x4)(ref result))[1, 0] = array[1];
				((Matrix4x4)(ref result))[2, 0] = array[2];
				((Matrix4x4)(ref result))[3, 0] = array[3];
				((Matrix4x4)(ref result))[0, 1] = array[4];
				((Matrix4x4)(ref result))[1, 1] = array[5];
				((Matrix4x4)(ref result))[2, 1] = array[6];
				((Matrix4x4)(ref result))[3, 1] = array[7];
				((Matrix4x4)(ref result))[0, 2] = array[8];
				((Matrix4x4)(ref result))[1, 2] = array[9];
				((Matrix4x4)(ref result))[2, 2] = array[10];
				((Matrix4x4)(ref result))[3, 2] = array[11];
				((Matrix4x4)(ref result))[0, 3] = array[12];
				((Matrix4x4)(ref result))[1, 3] = array[13];
				((Matrix4x4)(ref result))[2, 3] = array[14];
				((Matrix4x4)(ref result))[3, 3] = array[15];
				return result;
			}
			float[] array2 = new float[3];
			float[] array3 = new float[4] { 0f, 0f, 0f, 1f };
			float[] array4 = new float[3] { 1f, 1f, 1f };
			if (node.TryGetProperty("translation", out var value2))
			{
				array2 = (from e in value2.EnumerateArray()
					select e.GetSingle()).ToArray();
			}
			if (node.TryGetProperty("rotation", out var value3))
			{
				array3 = (from e in value3.EnumerateArray()
					select e.GetSingle()).ToArray();
			}
			if (node.TryGetProperty("scale", out var value4))
			{
				array4 = (from e in value4.EnumerateArray()
					select e.GetSingle()).ToArray();
			}
			float num = array3[0];
			float num2 = array3[1];
			float num3 = array3[2];
			float num4 = array3[3];
			float num5 = 1f - 2f * (num2 * num2 + num3 * num3);
			float num6 = 2f * (num * num2 - num3 * num4);
			float num7 = 2f * (num * num3 + num2 * num4);
			float num8 = 2f * (num * num2 + num3 * num4);
			float num9 = 1f - 2f * (num * num + num3 * num3);
			float num10 = 2f * (num2 * num3 - num * num4);
			float num11 = 2f * (num * num3 - num2 * num4);
			float num12 = 2f * (num2 * num3 + num * num4);
			float num13 = 1f - 2f * (num * num + num2 * num2);
			Matrix4x4 result2 = default(Matrix4x4);
			((Matrix4x4)(ref result2))[0, 0] = num5 * array4[0];
			((Matrix4x4)(ref result2))[0, 1] = num6 * array4[1];
			((Matrix4x4)(ref result2))[0, 2] = num7 * array4[2];
			((Matrix4x4)(ref result2))[0, 3] = array2[0];
			((Matrix4x4)(ref result2))[1, 0] = num8 * array4[0];
			((Matrix4x4)(ref result2))[1, 1] = num9 * array4[1];
			((Matrix4x4)(ref result2))[1, 2] = num10 * array4[2];
			((Matrix4x4)(ref result2))[1, 3] = array2[1];
			((Matrix4x4)(ref result2))[2, 0] = num11 * array4[0];
			((Matrix4x4)(ref result2))[2, 1] = num12 * array4[1];
			((Matrix4x4)(ref result2))[2, 2] = num13 * array4[2];
			((Matrix4x4)(ref result2))[2, 3] = array2[2];
			((Matrix4x4)(ref result2))[3, 0] = 0f;
			((Matrix4x4)(ref result2))[3, 1] = 0f;
			((Matrix4x4)(ref result2))[3, 2] = 0f;
			((Matrix4x4)(ref result2))[3, 3] = 1f;
			return result2;
		}

		private static Vector3[] ReadVec3(byte[] data, int binStart, JsonElement accessor, JsonElement bufferViews)
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			int @int = accessor.GetProperty("count").GetInt32();
			int int2 = accessor.GetProperty("bufferView").GetInt32();
			JsonElement jsonElement = bufferViews[int2];
			JsonElement value;
			int num = (jsonElement.TryGetProperty("byteOffset", out value) ? value.GetInt32() : 0);
			JsonElement value2;
			int num2 = (accessor.TryGetProperty("byteOffset", out value2) ? value2.GetInt32() : 0);
			JsonElement value3;
			int num3 = (jsonElement.TryGetProperty("byteStride", out value3) ? value3.GetInt32() : 12);
			int num4 = binStart + num + num2;
			Vector3[] array = (Vector3[])(object)new Vector3[@int];
			for (int i = 0; i < @int; i++)
			{
				int num5 = num4 + i * num3;
				array[i] = new Vector3(BitConverter.ToSingle(data, num5), BitConverter.ToSingle(data, num5 + 4), BitConverter.ToSingle(data, num5 + 8));
			}
			return array;
		}

		private static Vector2[] ReadVec2(byte[] data, int binStart, JsonElement accessor, JsonElement bufferViews)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			int @int = accessor.GetProperty("count").GetInt32();
			int int2 = accessor.GetProperty("bufferView").GetInt32();
			JsonElement jsonElement = bufferViews[int2];
			JsonElement value;
			int num = (jsonElement.TryGetProperty("byteOffset", out value) ? value.GetInt32() : 0);
			JsonElement value2;
			int num2 = (accessor.TryGetProperty("byteOffset", out value2) ? value2.GetInt32() : 0);
			JsonElement value3;
			int num3 = (jsonElement.TryGetProperty("byteStride", out value3) ? value3.GetInt32() : 8);
			int num4 = binStart + num + num2;
			Vector2[] array = (Vector2[])(object)new Vector2[@int];
			for (int i = 0; i < @int; i++)
			{
				int num5 = num4 + i * num3;
				array[i] = new Vector2(BitConverter.ToSingle(data, num5), 1f - BitConverter.ToSingle(data, num5 + 4));
			}
			return array;
		}

		private static int[] ReadIndices(byte[] data, int binStart, JsonElement accessor, JsonElement bufferViews)
		{
			int @int = accessor.GetProperty("count").GetInt32();
			int int2 = accessor.GetProperty("bufferView").GetInt32();
			JsonElement value;
			int num = (bufferViews[int2].TryGetProperty("byteOffset", out value) ? value.GetInt32() : 0);
			JsonElement value2;
			int num2 = (accessor.TryGetProperty("byteOffset", out value2) ? value2.GetInt32() : 0);
			int int3 = accessor.GetProperty("componentType").GetInt32();
			int num3 = binStart + num + num2;
			int[] array = new int[@int];
			switch (int3)
			{
			case 5125:
			{
				for (int j = 0; j < @int; j++)
				{
					array[j] = (int)BitConverter.ToUInt32(data, num3 + j * 4);
				}
				break;
			}
			case 5123:
			{
				for (int k = 0; k < @int; k++)
				{
					array[k] = BitConverter.ToUInt16(data, num3 + k * 2);
				}
				break;
			}
			default:
			{
				for (int i = 0; i < @int; i++)
				{
					array[i] = data[num3 + i];
				}
				break;
			}
			}
			return array;
		}
	}
}