Decompiled source of PEAK LEGO EDITION v1.0.8

BepInEx/plugins/Furter-LegoSkin/Furter.LegoSkin.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Furter.LegoSkin
{
	[BepInPlugin("Furter.LegoSkin", "LEGO Skin", "5.0.0")]
	public class LegoSkinPlugin : BaseUnityPlugin
	{
		public static ConfigEntry<float> CamDistance;

		public static ConfigEntry<float> CamHeight;

		public static ConfigEntry<float> CamFov;

		public static float CamDistOffset = 0f;

		public static float CamHeightOffset = 0f;

		public static float CamZoom = 3f;

		public static float GlobalYawNudge = -4f;

		public static bool DisableBody = false;

		public static ConfigEntry<float> LegoScale;

		public static ConfigEntry<string> SelectedCharacter;

		public static bool CameraEnabled = true;

		public static int CameraMode = 0;

		public static Transform HeadPivot;

		public static float ArmSpreadMult = 0.95f;

		public static float MouthSensitivity = 12f;

		public static float LegSwing = 1f;

		public static readonly string[] CameraModeNames = new string[2] { "1st Person", "BF2015 3rd Person" };

		public static LegoSkinPlugin Instance;

		private string _pluginDir;

		private List<string> _characters = new List<string>();

		private int _charIndex;

		private Harmony _harmony;

		private bool _legoApplied;

		private Character _lastCharacter;

		private bool _bonesDumped;

		private Item _lastHeldItem;

		private Dictionary<Character, string> _remoteSkins = new Dictionary<Character, string>();

		private float _syncTimer;

		private static readonly Dictionary<string, Texture2D> _texCache = new Dictionary<string, Texture2D>();

		private static readonly Dictionary<string, Material> _matCache = new Dictionary<string, Material>();

		private List<string> _allHeadDirs = new List<string>();

		private int _headIndex;

		private readonly Dictionary<string, int> _partCharIdx = new Dictionary<string, int>();

		private List<string> _allAccessoryPaths = new List<string>();

		private int _accessoryIndex = -1;

		private bool _treesReplaced;

		private GameObject _legoTreeTemplate;

		private float _treeNativeExtent;

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

		private readonly List<GameObject> _spawnedTrees = new List<GameObject>();

		private GameObject _currentHeadMesh;

		private GameObject _currentAccessory;

		private Transform _headPivot;

		private int _handColorIndex;

		private static readonly Color[] HandColors = (Color[])(object)new Color[9]
		{
			new Color(0.95f, 0.8f, 0.2f, 1f),
			new Color(0.85f, 0.65f, 0.13f, 1f),
			new Color(0.45f, 0.3f, 0.14f, 1f),
			new Color(0.3f, 0.18f, 0.1f, 1f),
			new Color(0.95f, 0.9f, 0.8f, 1f),
			new Color(0.15f, 0.15f, 0.15f, 1f),
			new Color(0.9f, 0.9f, 0.9f, 1f),
			new Color(0.8f, 0f, 0f, 1f),
			new Color(0f, 0.5f, 0f, 1f)
		};

		private static MethodInfo _loadImageMethod;

		private static MethodInfo _playEmoteMethod;

		private static readonly string[] TreeCanopyKeywords = new string[6] { "crown", "foliage", "leaves", "treeflower", "pineleaves", "pine berry" };

		private static readonly string[] TreeTrunkKeywords = new string[3] { "trunk", "gianttree", "tree platform" };

		private float _chromeMetallic = 1f;

		private float _chromeSmoothness = 0.9f;

		private Color _chromeTint = Color.white;

		private bool _hasChromeTint;

		private float _chromeEmission;

		private float _translucentAlpha = 1f;

		private string CurrentModelsDir
		{
			get
			{
				if (_characters.Count <= 0)
				{
					return null;
				}
				return Path.Combine(_pluginDir, _characters[_charIndex]);
			}
		}

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Expected O, but got Unknown
			Instance = this;
			CamDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Distance", 2f, new ConfigDescription("Camera distance", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			CamHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Height", 0.3f, new ConfigDescription("Camera height", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 5f), Array.Empty<object>()));
			CamFov = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "FieldOfView", 75f, new ConfigDescription("Camera FOV", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 170f), Array.Empty<object>()));
			LegoScale = ((BaseUnityPlugin)this).Config.Bind<float>("LEGO", "Scale", 2f, new ConfigDescription("Extra scale multiplier", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
			SelectedCharacter = ((BaseUnityPlugin)this).Config.Bind<string>("LEGO", "Character", "TwoFace", "Active character");
			_pluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			ScanCharacters();
			_playEmoteMethod = typeof(CharacterAnimations).GetMethod("PlayEmote", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
			if (type != null)
			{
				_loadImageMethod = type.GetMethod("LoadImage", new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				});
			}
			_harmony = new Harmony("Furter.LegoSkin");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"LEGO Skin v5.0.0 -- {_characters.Count} characters");
		}

		private void ScanCharacters()
		{
			_characters.Clear();
			_allHeadDirs.Clear();
			_allAccessoryPaths.Clear();
			string[] directories = Directory.GetDirectories(_pluginDir);
			foreach (string text in directories)
			{
				string fileName = Path.GetFileName(text);
				if (File.Exists(Path.Combine(text, "head.obj")))
				{
					_characters.Add(fileName);
					_allHeadDirs.Add(text);
				}
				string[] files = Directory.GetFiles(text, "*.obj");
				foreach (string text2 in files)
				{
					string text3 = Path.GetFileNameWithoutExtension(text2).ToLower();
					if (text3.StartsWith("helmet") || text3.StartsWith("mask") || text3.StartsWith("hat") || text3.StartsWith("glasses") || text3.StartsWith("hair") || text3.StartsWith("accessory") || text3.StartsWith("visor") || text3.StartsWith("hood") || text3.StartsWith("crown") || text3.StartsWith("cap"))
					{
						_allAccessoryPaths.Add(text2);
					}
				}
			}
			_characters.Sort();
			_allHeadDirs.Sort();
			_charIndex = _characters.IndexOf(SelectedCharacter.Value);
			if (_charIndex < 0)
			{
				_charIndex = 0;
			}
			_headIndex = _charIndex;
		}

		private static string ChessSkinFor(string mn)
		{
			if (mn.Contains("king"))
			{
				return "Vader";
			}
			if (mn.Contains("queen"))
			{
				return "Leia";
			}
			if (mn.Contains("bishop"))
			{
				if (!mn.Contains("_f"))
				{
					return "QuiGon";
				}
				return "ObiWan";
			}
			if (mn.Contains("knight"))
			{
				return "BobaFett";
			}
			if (mn.Contains("rook"))
			{
				if (!mn.Contains("_f"))
				{
					return "DarthMaul";
				}
				return "Chewbacca";
			}
			if (mn.Contains("pawn"))
			{
				if (!mn.Contains("_f"))
				{
					return "Batman";
				}
				return "Stormtrooper";
			}
			return null;
		}

		private void CyclePart(string cat)
		{
			if (_characters.Count != 0)
			{
				int value;
				int num = ((_partCharIdx.TryGetValue(cat, out value) ? value : _charIndex) + 1) % _characters.Count;
				_partCharIdx[cat] = num;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Part [" + cat + "] -> " + _characters[num]));
				CleanupLego();
				_legoApplied = false;
			}
		}

		private static string PartCategory(string partFile)
		{
			if (partFile.StartsWith("head"))
			{
				return "head";
			}
			if (partFile.StartsWith("torso"))
			{
				return "torso";
			}
			if (partFile.StartsWith("arms"))
			{
				return "arms";
			}
			if (partFile.StartsWith("legs"))
			{
				return "legs";
			}
			return null;
		}

		private string PartSourceDir(string partFile, string baseDir)
		{
			string text = PartCategory(partFile);
			if (text == null)
			{
				return baseDir;
			}
			if (_partCharIdx.TryGetValue(text, out var value) && value >= 0 && value < _characters.Count)
			{
				string text2 = Path.Combine(_pluginDir, _characters[value]);
				if (Directory.Exists(text2))
				{
					return text2;
				}
			}
			return baseDir;
		}

		private void Update()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			bool flag = ((Scene)(ref activeScene)).name.ToLowerInvariant().Contains("airport");
			if (Input.GetKeyDown((KeyCode)286) || Input.GetKeyDown((KeyCode)334))
			{
				CamZoom = ((CamZoom < 0.7f) ? 3f : 0.4f);
				CameraEnabled = true;
				Camera main = Camera.main;
				if ((Object)(object)main != (Object)null)
				{
					main.orthographic = false;
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Camera: {0} (zoom {1:F1})", (CamZoom < 0.7f) ? "First Person" : "Third Person", CamZoom));
			}
			if (flag && !DisableBody && (Input.GetKeyDown((KeyCode)287) || Input.GetKeyDown((KeyCode)335)) && _characters.Count > 1)
			{
				_charIndex = (_charIndex + 1) % _characters.Count;
				SelectedCharacter.Value = _characters[_charIndex];
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Switched to: " + _characters[_charIndex]));
				_partCharIdx.Clear();
				CleanupLego();
				_legoApplied = false;
				BroadcastSkin();
			}
			if (!DisableBody && (Object)(object)_lastCharacter != (Object)null && (Object)(object)_lastCharacter.data != (Object)null && _characters.Count > 0)
			{
				Item currentItem = _lastCharacter.data.currentItem;
				if ((Object)(object)currentItem != (Object)(object)_lastHeldItem)
				{
					_lastHeldItem = currentItem;
					if ((Object)(object)currentItem != (Object)null)
					{
						string text = null;
						MeshFilter[] componentsInChildren = ((Component)currentItem).GetComponentsInChildren<MeshFilter>(true);
						foreach (MeshFilter val in componentsInChildren)
						{
							if (!((Object)(object)val.sharedMesh == (Object)null))
							{
								string text2 = ((Object)val.sharedMesh).name.ToLowerInvariant();
								if (text2.Contains("king") || text2.Contains("queen") || text2.Contains("bishop") || text2.Contains("knight") || text2.Contains("rook") || text2.Contains("pawn"))
								{
									text = ChessSkinFor(text2);
									break;
								}
							}
						}
						if (text != null && _characters.Contains(text))
						{
							int num = _characters.IndexOf(text);
							if (num >= 0 && num != _charIndex)
							{
								_charIndex = num;
								SelectedCharacter.Value = text;
								_partCharIdx.Clear();
								CleanupLego();
								_legoApplied = false;
								((BaseUnityPlugin)this).Logger.LogInfo((object)("Chess pickup '" + ((Object)currentItem).name + "' -> wearing " + text));
							}
						}
					}
				}
			}
			if (flag && !DisableBody && (Input.GetKeyDown((KeyCode)284) || Input.GetKeyDown((KeyCode)288)))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Refresh (F3) — reloading LEGO skin");
				ScanCharacters();
				CleanupLego();
				_legoApplied = false;
			}
			if (Input.GetKey((KeyCode)273))
			{
				CamZoom = Mathf.Max(0f, CamZoom - 4f * Time.deltaTime);
			}
			if (Input.GetKey((KeyCode)274))
			{
				CamZoom = Mathf.Min(8f, CamZoom + 4f * Time.deltaTime);
			}
			if (Input.GetKeyDown((KeyCode)45))
			{
				CamDistOffset -= 0.1f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"cam dist offset {CamDistOffset:F2}");
			}
			if (Input.GetKeyDown((KeyCode)61))
			{
				CamDistOffset += 0.1f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"cam dist offset {CamDistOffset:F2}");
			}
			if (Input.GetKeyDown((KeyCode)91))
			{
				CamHeightOffset -= 0.1f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"cam height offset {CamHeightOffset:F2}");
			}
			if (Input.GetKeyDown((KeyCode)93))
			{
				CamHeightOffset += 0.1f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"cam height offset {CamHeightOffset:F2}");
			}
			if (Input.GetKeyDown((KeyCode)44))
			{
				GlobalYawNudge -= 1f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"global yaw nudge {GlobalYawNudge:F0}");
			}
			if (Input.GetKeyDown((KeyCode)46))
			{
				GlobalYawNudge += 1f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"global yaw nudge {GlobalYawNudge:F0}");
			}
			if (flag)
			{
				if (Input.GetKeyDown((KeyCode)257))
				{
					CyclePart("head");
				}
				if (Input.GetKeyDown((KeyCode)258))
				{
					CyclePart("torso");
				}
				if (Input.GetKeyDown((KeyCode)259))
				{
					CyclePart("arms");
				}
				if (Input.GetKeyDown((KeyCode)260))
				{
					CyclePart("legs");
				}
				if (Input.GetKeyDown((KeyCode)256))
				{
					_partCharIdx.Clear();
					CleanupLego();
					_legoApplied = false;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Parts reset to current character");
				}
				if (Input.GetKeyDown((KeyCode)270))
				{
					ArmSpreadMult += 0.05f;
					CleanupLego();
					_legoApplied = false;
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"arm spread {ArmSpreadMult:F2}");
				}
				if (Input.GetKeyDown((KeyCode)269))
				{
					ArmSpreadMult = Mathf.Max(0.5f, ArmSpreadMult - 0.05f);
					CleanupLego();
					_legoApplied = false;
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"arm spread {ArmSpreadMult:F2}");
				}
				if (Input.GetKeyDown((KeyCode)268))
				{
					LegSwing += 0.15f;
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"leg swing {LegSwing:F2}");
				}
				if (Input.GetKeyDown((KeyCode)267))
				{
					LegSwing = Mathf.Max(0f, LegSwing - 0.15f);
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"leg swing {LegSwing:F2}");
				}
			}
			if (Input.GetKeyDown((KeyCode)289))
			{
				Player localPlayer = Player.localPlayer;
				if ((Object)(object)((localPlayer != null) ? localPlayer.character : null) != (Object)null)
				{
					DumpCharacterMesh(localPlayer.character);
				}
			}
			if (!DisableBody && Input.GetKeyDown((KeyCode)290) && _allHeadDirs.Count > 0)
			{
				_headIndex = (_headIndex + 1) % _allHeadDirs.Count;
				string fileName = Path.GetFileName(_allHeadDirs[_headIndex]);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Head swap -> " + fileName));
				SwapHead(_allHeadDirs[_headIndex]);
			}
			if (!DisableBody && Input.GetKeyDown((KeyCode)285) && _allAccessoryPaths.Count > 0)
			{
				_accessoryIndex++;
				if (_accessoryIndex >= _allAccessoryPaths.Count)
				{
					_accessoryIndex = -1;
				}
				if (_accessoryIndex < 0)
				{
					RemoveAccessory();
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Accessory removed");
				}
				else
				{
					string text3 = _allAccessoryPaths[_accessoryIndex];
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Accessory -> " + Path.GetFileName(text3)));
					ApplyAccessory(text3);
				}
			}
			if (Input.GetKeyDown((KeyCode)291))
			{
				string text4 = Path.Combine(_pluginDir, "Screenshots");
				Directory.CreateDirectory(text4);
				string text5 = $"lego_{DateTime.Now:yyyyMMdd_HHmmss_fff}.png";
				ScreenCapture.CaptureScreenshot(Path.Combine(text4, text5));
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Screenshot: " + text5));
			}
			if (Input.GetKeyDown((KeyCode)292))
			{
				Player localPlayer2 = Player.localPlayer;
				if ((Object)(object)((localPlayer2 != null) ? localPlayer2.character : null) != (Object)null)
				{
					DumpPeakReference(localPlayer2.character);
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"F11: no local player character to capture");
				}
			}
			if (Input.GetKeyDown((KeyCode)293))
			{
				if (_treesReplaced)
				{
					RestoreTrees();
				}
				else
				{
					ReplaceTrees();
				}
			}
			if (DisableBody)
			{
				return;
			}
			Player localPlayer3 = Player.localPlayer;
			if ((Object)(object)localPlayer3 == (Object)null || (Object)(object)localPlayer3.character == (Object)null)
			{
				_legoApplied = false;
				_lastCharacter = null;
			}
			else
			{
				Character character = localPlayer3.character;
				if (!_legoApplied || (Object)(object)character != (Object)(object)_lastCharacter)
				{
					if ((Object)(object)character != (Object)(object)_lastCharacter)
					{
						CleanupLego();
						_legoApplied = false;
					}
					_lastCharacter = character;
					ApplyLegoSkin(character);
					BroadcastSkin();
				}
			}
			_syncTimer += Time.deltaTime;
			if (_syncTimer >= 0.5f)
			{
				_syncTimer = 0f;
				SyncRemotePlayers();
			}
		}

		private static bool ContainsAny(string n, string[] keys)
		{
			foreach (string value in keys)
			{
				if (n.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private void EnsureLegoTreeTemplate()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_017d: 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_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: 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)
			//IL_019c: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_0124: 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)
			if ((Object)(object)_legoTreeTemplate != (Object)null)
			{
				return;
			}
			string path = Path.Combine(_pluginDir, "_props", "LegoTree");
			string text = Path.Combine(path, "legotree.obj");
			if (!File.Exists(text))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("F12: legotree.obj not found at " + text));
				return;
			}
			ObjResult objResult = ObjLoader.Load(text);
			Dictionary<string, MtlInfo> dictionary = ObjLoader.ParseMtl(Path.Combine(path, "legotree.mtl"));
			GameObject val = new GameObject("LegoTreeTemplate");
			val.SetActive(false);
			val.AddComponent<MeshFilter>().sharedMesh = objResult.Mesh;
			MeshRenderer val2 = val.AddComponent<MeshRenderer>();
			Shader val3 = Shader.Find("Universal Render Pipeline/Lit");
			Material[] array = (Material[])(object)new Material[objResult.MaterialNames.Length];
			for (int i = 0; i < array.Length; i++)
			{
				MtlInfo mtlInfo = (dictionary.ContainsKey(objResult.MaterialNames[i]) ? dictionary[objResult.MaterialNames[i]] : null);
				Color val4 = ((mtlInfo != null && mtlInfo.HasKdColor) ? mtlInfo.KdColor : Color.gray);
				Material val5 = (((Object)(object)val3 != (Object)null) ? new Material(val3) : new Material(((Renderer)val2).material));
				val5.SetColor("_BaseColor", val4);
				val5.color = val4;
				val5.SetFloat("_Smoothness", 0.85f);
				val5.SetFloat("_Metallic", 0f);
				array[i] = val5;
			}
			((Renderer)val2).sharedMaterials = array;
			Bounds bounds = objResult.Mesh.bounds;
			Vector3 size = ((Bounds)(ref bounds)).size;
			_treeNativeExtent = Mathf.Max(size.x, Mathf.Max(size.y, size.z));
			if (_treeNativeExtent < 0.001f)
			{
				_treeNativeExtent = 1f;
			}
			Object.DontDestroyOnLoad((Object)(object)val);
			_legoTreeTemplate = val;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"LEGO tree template: {objResult.Mesh.vertexCount}v, extent {_treeNativeExtent:F2}, {array.Length} colors");
		}

		private void ReplaceTrees()
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: 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_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: 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_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			EnsureLegoTreeTemplate();
			if ((Object)(object)_legoTreeTemplate == (Object)null)
			{
				return;
			}
			float result = 270f;
			float result2 = 0f;
			float result3 = 0f;
			float result4 = 1f;
			float result5 = 0f;
			string path = Path.Combine(_pluginDir, "_props", "LegoTree", "treeconfig.txt");
			if (File.Exists(path))
			{
				string[] array = File.ReadAllText(path).Split(new char[5] { ' ', ',', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				if (array.Length != 0)
				{
					float.TryParse(array[0], NumberStyles.Float, invariantCulture, out result);
				}
				if (array.Length > 1)
				{
					float.TryParse(array[1], NumberStyles.Float, invariantCulture, out result2);
				}
				if (array.Length > 2)
				{
					float.TryParse(array[2], NumberStyles.Float, invariantCulture, out result3);
				}
				if (array.Length > 3)
				{
					float.TryParse(array[3], NumberStyles.Float, invariantCulture, out result4);
				}
				if (array.Length > 4)
				{
					float.TryParse(array[4], NumberStyles.Float, invariantCulture, out result5);
				}
			}
			Quaternion rotation = Quaternion.Euler(result, result2, result3);
			int num = 0;
			int num2 = 0;
			MeshFilter[] array2 = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array2)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null || !((Renderer)component).enabled)
				{
					continue;
				}
				string text = ((Object)val.sharedMesh).name.ToLowerInvariant();
				bool flag = false;
				Material[] sharedMaterials = ((Renderer)component).sharedMaterials;
				if (sharedMaterials != null)
				{
					Material[] array3 = sharedMaterials;
					foreach (Material val2 in array3)
					{
						if ((Object)(object)val2 != (Object)null && ((Object)val2).name.ToLowerInvariant().Contains("palm"))
						{
							flag = true;
							break;
						}
					}
				}
				if (!flag && ContainsAny(text, TreeCanopyKeywords))
				{
					((Renderer)component).enabled = false;
					_hiddenTreeRenderers.Add((Renderer)(object)component);
					num2++;
				}
				else if (flag || text == "tree" || ContainsAny(text, TreeTrunkKeywords))
				{
					Bounds bounds = ((Renderer)component).bounds;
					float num3 = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z)) / _treeNativeExtent * result4;
					GameObject val3 = Object.Instantiate<GameObject>(_legoTreeTemplate);
					((Object)val3).name = "LegoTree";
					val3.transform.position = new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y + result5, ((Bounds)(ref bounds)).center.z);
					val3.transform.rotation = rotation;
					val3.transform.localScale = Vector3.one * num3;
					val3.SetActive(true);
					_spawnedTrees.Add(val3);
					((Renderer)component).enabled = false;
					_hiddenTreeRenderers.Add((Renderer)(object)component);
					num++;
				}
			}
			_treesReplaced = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"F12: {num} trees replaced (+{num2} canopies hidden). rot=({result},{result2},{result3}) scaleMult={result4} yOff={result5}");
		}

		private void RestoreTrees()
		{
			foreach (GameObject spawnedTree in _spawnedTrees)
			{
				if ((Object)(object)spawnedTree != (Object)null)
				{
					Object.Destroy((Object)(object)spawnedTree);
				}
			}
			_spawnedTrees.Clear();
			foreach (Renderer hiddenTreeRenderer in _hiddenTreeRenderers)
			{
				if ((Object)(object)hiddenTreeRenderer != (Object)null)
				{
					hiddenTreeRenderer.enabled = true;
				}
			}
			_hiddenTreeRenderers.Clear();
			_treesReplaced = false;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"F12: trees restored");
		}

		private void BroadcastSkin()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			try
			{
				if (PhotonNetwork.IsConnected && PhotonNetwork.InRoom && _characters.Count > 0)
				{
					Hashtable val = new Hashtable();
					val[(object)"LegoSkin"] = _characters[_charIndex];
					PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Broadcast skin: " + _characters[_charIndex]));
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Broadcast failed: " + ex.Message));
			}
		}

		private void SyncRemotePlayers()
		{
			try
			{
				if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom)
				{
					return;
				}
				List<Character> list = new List<Character>();
				foreach (KeyValuePair<Character, string> remoteSkin in _remoteSkins)
				{
					if ((Object)(object)remoteSkin.Key == (Object)null)
					{
						list.Add(remoteSkin.Key);
					}
				}
				foreach (Character item in list)
				{
					_remoteSkins.Remove(item);
				}
				Player[] array = Object.FindObjectsByType<Player>((FindObjectsSortMode)0);
				foreach (Player val in array)
				{
					if ((Object)(object)val == (Object)(object)Player.localPlayer || (Object)(object)((val != null) ? val.character : null) == (Object)null)
					{
						continue;
					}
					PhotonView val2 = ((Component)val).GetComponent<PhotonView>();
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = ((Component)val).GetComponentInChildren<PhotonView>();
					}
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = ((Component)val).GetComponentInParent<PhotonView>();
					}
					if (((val2 != null) ? val2.Owner : null) == null || !((Dictionary<object, object>)(object)val2.Owner.CustomProperties).TryGetValue((object)"LegoSkin", out object value))
					{
						continue;
					}
					string text = value as string;
					if (!string.IsNullOrEmpty(text) && (!_remoteSkins.TryGetValue(val.character, out var value2) || !(value2 == text)))
					{
						string text2 = Path.Combine(_pluginDir, text);
						if (Directory.Exists(text2))
						{
							CleanupLegoOn(val.character);
							ApplyLegoSkin(val.character, text2);
							_remoteSkins[val.character] = text;
							((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied remote skin: " + text + " on " + ((Object)val).name));
						}
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Remote sync error: " + ex.Message));
			}
		}

		private void CleanupLegoOn(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return;
			}
			Transform[] componentsInChildren = ((Component)character).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name == "LegoRoot")
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			RestoreOriginalBody(character);
		}

		private void RestoreOriginalBody(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return;
			}
			SkinnedMeshRenderer mainRenderer = character.refs.mainRenderer;
			if ((Object)(object)mainRenderer != (Object)null)
			{
				((Renderer)mainRenderer).shadowCastingMode = (ShadowCastingMode)1;
			}
			Renderer[] componentsInChildren = ((Component)character).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (((Object)((Component)val).gameObject).name.Contains("Lego_") || ((Object)((Component)val).gameObject).name.Contains("LegoMouth"))
				{
					continue;
				}
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null);
				if (val2 != null)
				{
					((Renderer)val2).shadowCastingMode = (ShadowCastingMode)1;
					continue;
				}
				MeshRenderer val3 = (MeshRenderer)(object)((val is MeshRenderer) ? val : null);
				if (val3 != null)
				{
					((Renderer)val3).shadowCastingMode = (ShadowCastingMode)1;
				}
			}
		}

		private Transform FindBone(Transform[] bones, params string[] patterns)
		{
			if (bones == null)
			{
				return null;
			}
			foreach (string text in patterns)
			{
				foreach (Transform val in bones)
				{
					if ((Object)(object)val != (Object)null && ((Object)val).name.ToLower().Contains(text.ToLower()))
					{
						return val;
					}
				}
			}
			return null;
		}

		private Transform FindBoneExact(Transform[] bones, params string[] names)
		{
			if (bones == null)
			{
				return null;
			}
			foreach (string text in names)
			{
				foreach (Transform val in bones)
				{
					if ((Object)(object)val != (Object)null && ((Object)val).name == text)
					{
						return val;
					}
				}
			}
			return null;
		}

		private Texture2D LoadTexture(string path)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if (!File.Exists(path))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Texture file not found: " + path));
				return null;
			}
			byte[] array = File.ReadAllBytes(path);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
			if (_loadImageMethod != null)
			{
				if (!(bool)_loadImageMethod.Invoke(null, new object[2] { val, array }))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)$"LoadImage failed for: {Path.GetFileName(path)} ({array.Length} bytes)");
					Object.Destroy((Object)(object)val);
					return null;
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded texture: {Path.GetFileName(path)} ({((Texture)val).width}x{((Texture)val).height})");
				((Texture)val).filterMode = (FilterMode)1;
				Object.DontDestroyOnLoad((Object)(object)val);
				return val;
			}
			((BaseUnityPlugin)this).Logger.LogWarning((object)"ImageConversion.LoadImage not available");
			Object.Destroy((Object)(object)val);
			return null;
		}

		private Material CreateMaterial(Material baseMat, Texture2D tex, Color baseColor, bool needsAlpha = false, Texture2D normalMap = null, bool isChrome = false, bool isGlass = false, bool isMatte = false)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_0172: 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_02c3: 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_017d: 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_0196: 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_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Universal Render Pipeline/Lit");
			Material val2 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(baseMat));
			if ((Object)(object)tex != (Object)null)
			{
				val2.mainTexture = (Texture)(object)tex;
				val2.SetTexture("_BaseMap", (Texture)(object)tex);
				val2.SetColor("_BaseColor", Color.white);
				val2.color = Color.white;
			}
			else
			{
				Texture2D val3 = new Texture2D(4, 4, (TextureFormat)4, false);
				Color[] array = (Color[])(object)new Color[16];
				for (int i = 0; i < 16; i++)
				{
					array[i] = baseColor;
				}
				val3.SetPixels(array);
				val3.Apply();
				((Texture)val3).filterMode = (FilterMode)0;
				val2.mainTexture = (Texture)(object)val3;
				val2.SetTexture("_BaseMap", (Texture)(object)val3);
				val2.SetColor("_BaseColor", Color.white);
				val2.color = Color.white;
			}
			val2.SetFloat("_Smoothness", isChrome ? _chromeSmoothness : (isMatte ? 0.12f : 0.9f));
			val2.SetFloat("_Metallic", isChrome ? _chromeMetallic : 0f);
			val2.SetFloat("_GlossMapScale", 1f);
			if (isChrome && _hasChromeTint)
			{
				val2.SetColor("_BaseColor", _chromeTint);
				val2.color = _chromeTint;
			}
			if (isChrome && _chromeEmission > 0f)
			{
				val2.EnableKeyword("_EMISSION");
				Color val4 = (_hasChromeTint ? _chromeTint : Color.white) * _chromeEmission;
				val4.a = 1f;
				val2.SetColor("_EmissionColor", val4);
				if ((Object)(object)tex != (Object)null)
				{
					val2.SetTexture("_EmissionMap", (Texture)(object)tex);
				}
				val2.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)1;
			}
			if ((Object)(object)normalMap != (Object)null)
			{
				val2.SetTexture("_BumpMap", (Texture)(object)normalMap);
				val2.SetFloat("_BumpScale", 1f);
				val2.EnableKeyword("_NORMALMAP");
			}
			if (needsAlpha)
			{
				val2.SetFloat("_AlphaClip", 1f);
				val2.SetFloat("_Cutoff", 0.5f);
				val2.EnableKeyword("_ALPHATEST_ON");
				val2.renderQueue = 2450;
			}
			if (isGlass)
			{
				val2.SetFloat("_Surface", 1f);
				val2.SetFloat("_Blend", 0f);
				val2.SetOverrideTag("RenderType", "Transparent");
				val2.SetInt("_SrcBlend", 5);
				val2.SetInt("_DstBlend", 10);
				val2.SetInt("_ZWrite", 0);
				val2.DisableKeyword("_ALPHATEST_ON");
				val2.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
				val2.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				Color val5 = default(Color);
				((Color)(ref val5))..ctor(0.62f, 0.8f, 0.92f, 0.3f);
				val2.SetColor("_BaseColor", val5);
				val2.color = val5;
				val2.SetFloat("_Smoothness", 0.95f);
				val2.SetFloat("_Metallic", 0.1f);
				val2.renderQueue = 3050;
			}
			if (_translucentAlpha < 0.999f && !isGlass)
			{
				val2.SetFloat("_Surface", 1f);
				val2.SetFloat("_Blend", 0f);
				val2.SetOverrideTag("RenderType", "Transparent");
				val2.SetInt("_SrcBlend", 5);
				val2.SetInt("_DstBlend", 10);
				val2.SetInt("_ZWrite", 0);
				val2.DisableKeyword("_ALPHATEST_ON");
				val2.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
				Color color = val2.GetColor("_BaseColor");
				color.a = _translucentAlpha;
				val2.SetColor("_BaseColor", color);
				Color color2 = val2.color;
				color2.a = _translucentAlpha;
				val2.color = color2;
				val2.renderQueue = 3000;
			}
			if (val2.HasProperty("_Cull"))
			{
				val2.SetFloat("_Cull", 0f);
			}
			Object.DontDestroyOnLoad((Object)(object)val2);
			return val2;
		}

		private Material[] BuildMaterials(string modelsDir, string partFile, Material baseMat, Dictionary<string, Texture2D> texCache, Dictionary<string, Material> matCache, ObjResult result, bool isChrome = false)
		{
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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)
			Dictionary<string, MtlInfo> dictionary = ObjLoader.ParseMtl(Path.Combine(modelsDir, partFile + ".mtl"));
			HashSet<string> hashSet = new HashSet<string>();
			string path = Path.Combine(modelsDir, "glass.txt");
			if (File.Exists(path))
			{
				string[] array = File.ReadAllLines(path);
				foreach (string text in array)
				{
					if (!string.IsNullOrWhiteSpace(text))
					{
						hashSet.Add(text.Trim());
					}
				}
			}
			HashSet<string> hashSet2 = new HashSet<string>();
			string path2 = Path.Combine(modelsDir, "matte.txt");
			if (File.Exists(path2))
			{
				string[] array = File.ReadAllLines(path2);
				foreach (string text2 in array)
				{
					if (!string.IsNullOrWhiteSpace(text2))
					{
						hashSet2.Add(text2.Trim());
					}
				}
			}
			Material[] array2 = (Material[])(object)new Material[result.MaterialNames.Length];
			for (int j = 0; j < result.MaterialNames.Length; j++)
			{
				string text3 = result.MaterialNames[j];
				MtlInfo mtlInfo = (dictionary.ContainsKey(text3) ? dictionary[text3] : null);
				if (mtlInfo == null && dictionary.Count > 0)
				{
					using Dictionary<string, MtlInfo>.Enumerator enumerator = dictionary.GetEnumerator();
					if (enumerator.MoveNext())
					{
						KeyValuePair<string, MtlInfo> current = enumerator.Current;
						mtlInfo = current.Value;
						text3 = current.Key;
					}
				}
				string text4 = mtlInfo?.TexFile;
				Color baseColor = ((mtlInfo != null && mtlInfo.HasKdColor) ? mtlInfo.KdColor : Color.white);
				bool flag = partFile.Contains("head") && text4 != null && (text4.Contains("Face") || text4.Contains("face"));
				bool flag2 = hashSet.Contains(text3);
				bool flag3 = hashSet2.Contains("all") || hashSet2.Contains(partFile) || hashSet2.Contains(text3);
				string key = modelsDir + "|" + text3 + (flag ? "_alpha" : "") + (isChrome ? "_chrome" : "") + (flag2 ? "_glass" : "") + (flag3 ? "_matte" : "") + ((_translucentAlpha < 0.999f) ? ("_tl" + _translucentAlpha.ToString("0.00")) : "");
				if (!matCache.ContainsKey(key))
				{
					Texture2D tex = null;
					if (text4 != null)
					{
						string key2 = modelsDir + "|" + text4;
						if (!texCache.ContainsKey(key2))
						{
							texCache[key2] = LoadTexture(Path.Combine(modelsDir, text4));
						}
						tex = texCache[key2];
					}
					Texture2D normalMap = null;
					string text5 = mtlInfo?.NormalFile;
					if (text5 != null)
					{
						string key3 = modelsDir + "|" + text5;
						if (!texCache.ContainsKey(key3))
						{
							texCache[key3] = LoadTexture(Path.Combine(modelsDir, text5));
						}
						normalMap = texCache[key3];
					}
					matCache[key] = CreateMaterial(baseMat, tex, baseColor, flag, normalMap, isChrome, flag2, flag3);
				}
				array2[j] = matCache[key];
			}
			return array2;
		}

		private void ApplyLegoSkin(Character character, string overrideDir = null)
		{
			//IL_0916: Unknown result type (might be due to invalid IL or missing references)
			//IL_092a: Unknown result type (might be due to invalid IL or missing references)
			//IL_092f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0955: Unknown result type (might be due to invalid IL or missing references)
			//IL_095c: Expected O, but got Unknown
			//IL_0972: Unknown result type (might be due to invalid IL or missing references)
			//IL_0979: Unknown result type (might be due to invalid IL or missing references)
			//IL_0996: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_09c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0944: Unknown result type (might be due to invalid IL or missing references)
			//IL_0adf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ae6: Expected O, but got Unknown
			//IL_0c2b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c30: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d94: Unknown result type (might be due to invalid IL or missing references)
			//IL_0db0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ddc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ead: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e66: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e8f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e11: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e3a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f7e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f37: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f60: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ee2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f0b: Unknown result type (might be due to invalid IL or missing references)
			//IL_1117: Unknown result type (might be due to invalid IL or missing references)
			//IL_111c: Unknown result type (might be due to invalid IL or missing references)
			//IL_13e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_13ed: Expected O, but got Unknown
			//IL_1163: Unknown result type (might be due to invalid IL or missing references)
			//IL_1168: Unknown result type (might be due to invalid IL or missing references)
			//IL_19d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_19d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_19ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_19f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_19fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_1a00: Unknown result type (might be due to invalid IL or missing references)
			//IL_1a0a: Unknown result type (might be due to invalid IL or missing references)
			//IL_1a10: Unknown result type (might be due to invalid IL or missing references)
			//IL_1a1a: Unknown result type (might be due to invalid IL or missing references)
			//IL_1410: Unknown result type (might be due to invalid IL or missing references)
			//IL_1415: Unknown result type (might be due to invalid IL or missing references)
			//IL_1539: Unknown result type (might be due to invalid IL or missing references)
			//IL_1540: Expected O, but got Unknown
			//IL_155b: Unknown result type (might be due to invalid IL or missing references)
			//IL_1569: Unknown result type (might be due to invalid IL or missing references)
			//IL_157a: Unknown result type (might be due to invalid IL or missing references)
			//IL_14cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_14d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_14d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_14de: Unknown result type (might be due to invalid IL or missing references)
			//IL_1730: Unknown result type (might be due to invalid IL or missing references)
			//IL_1737: Expected O, but got Unknown
			//IL_1752: Unknown result type (might be due to invalid IL or missing references)
			//IL_1754: Unknown result type (might be due to invalid IL or missing references)
			//IL_1765: Unknown result type (might be due to invalid IL or missing references)
			//IL_1776: Unknown result type (might be due to invalid IL or missing references)
			//IL_17d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_17d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_17de: Unknown result type (might be due to invalid IL or missing references)
			//IL_17e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_17ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_17fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_1806: Unknown result type (might be due to invalid IL or missing references)
			//IL_180b: Unknown result type (might be due to invalid IL or missing references)
			//IL_1880: Unknown result type (might be due to invalid IL or missing references)
			//IL_1885: Unknown result type (might be due to invalid IL or missing references)
			//IL_188e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1895: Unknown result type (might be due to invalid IL or missing references)
			//IL_189f: Unknown result type (might be due to invalid IL or missing references)
			//IL_18a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_1979: Unknown result type (might be due to invalid IL or missing references)
			//IL_197e: Unknown result type (might be due to invalid IL or missing references)
			string text = overrideDir ?? CurrentModelsDir;
			if (text == null || !Directory.Exists(text))
			{
				return;
			}
			SkinnedMeshRenderer mainRenderer = character.refs.mainRenderer;
			Transform[] array = ((mainRenderer != null) ? mainRenderer.bones : null);
			Transform val = ((mainRenderer != null) ? mainRenderer.rootBone : null);
			if (!_bonesDumped && array != null)
			{
				_bonesDumped = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"=== PEAK Skeleton: {array.Length} bones ===");
				Transform[] array2 = array;
				foreach (Transform val2 in array2)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("  Bone: " + ((Object)val2).name + " (parent: " + (((Object)(object)val2.parent != (Object)null) ? ((Object)val2.parent).name : "none") + ")"));
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("  RootBone: " + ((Object)val).name));
				}
				Type type = ((object)character).GetType();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"=== Death/Ragdoll Methods ===");
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					string text2 = methodInfo.Name.ToLower();
					if (text2.Contains("die") || text2.Contains("death") || text2.Contains("dead") || text2.Contains("ragdoll") || text2.Contains("skeleton") || text2.Contains("kill") || text2.Contains("respawn") || text2.Contains("alive") || text2.Contains("health") || text2.Contains("damage") || text2.Contains("knockdown") || text2.Contains("downed"))
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("  " + methodInfo.Name + "(" + string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo p) => p.ParameterType.Name + " " + p.Name)) + ") -> " + methodInfo.ReturnType.Name));
					}
				}
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					string text3 = fieldInfo.Name.ToLower();
					if (text3.Contains("die") || text3.Contains("death") || text3.Contains("dead") || text3.Contains("ragdoll") || text3.Contains("skeleton") || text3.Contains("alive") || text3.Contains("health") || text3.Contains("downed"))
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("  Field: " + fieldInfo.Name + " (" + fieldInfo.FieldType.Name + ")"));
					}
				}
				PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo propertyInfo in properties)
				{
					string text4 = propertyInfo.Name.ToLower();
					if (text4.Contains("die") || text4.Contains("death") || text4.Contains("dead") || text4.Contains("ragdoll") || text4.Contains("skeleton") || text4.Contains("alive") || text4.Contains("health") || text4.Contains("downed"))
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("  Prop: " + propertyInfo.Name + " (" + propertyInfo.PropertyType.Name + ")"));
					}
				}
			}
			Transform val3 = FindBoneExact(array, "Hip") ?? FindBone(array, "hip", "pelvis");
			Transform val4 = FindBoneExact(array, "Mid") ?? FindBone(array, "mid", "spine");
			Transform val5 = FindBoneExact(array, "Head") ?? FindBone(array, "head");
			Transform val6 = FindBoneExact(array, "Arm_L") ?? FindBone(array, "arm_l", "upperarm_l", "shoulder_l");
			Transform val7 = FindBoneExact(array, "Arm_R") ?? FindBone(array, "arm_r", "upperarm_r", "shoulder_r");
			Transform val8 = FindBoneExact(array, "Leg_L") ?? FindBone(array, "leg_l", "thigh_l");
			Transform val9 = FindBoneExact(array, "Leg_R") ?? FindBone(array, "leg_r", "thigh_r");
			Transform val10 = FindBoneExact(array, "Hand_L") ?? FindBone(array, "hand_l");
			Transform val11 = FindBoneExact(array, "Hand_R") ?? FindBone(array, "hand_r");
			Transform val12 = val3 ?? val ?? ((Component)character).transform;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Bones: Hip=" + ((val3 != null) ? ((Object)val3).name : null) + " Mid=" + ((val4 != null) ? ((Object)val4).name : null) + " Head=" + ((val5 != null) ? ((Object)val5).name : null) + " ArmL=" + ((val6 != null) ? ((Object)val6).name : null) + " ArmR=" + ((val7 != null) ? ((Object)val7).name : null) + " LegL=" + ((val8 != null) ? ((Object)val8).name : null) + " LegR=" + ((val9 != null) ? ((Object)val9).name : null)));
			float result = 1f;
			string path = Path.Combine(text, "scale.txt");
			if (File.Exists(path))
			{
				float.TryParse(File.ReadAllText(path).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result);
				if (result <= 0f)
				{
					result = 1f;
				}
			}
			float num = 4.06f;
			string path2 = Path.Combine(text, "head.obj");
			if (File.Exists(path2))
			{
				float num2 = 0f;
				string[] array3 = File.ReadAllLines(path2);
				foreach (string text5 in array3)
				{
					if (text5.StartsWith("v "))
					{
						string[] array4 = text5.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
						if (array4.Length >= 3 && float.TryParse(array4[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && result2 > num2)
						{
							num2 = result2;
						}
					}
				}
				if (num2 > 1f)
				{
					num = num2;
				}
			}
			Dictionary<string, float> dictionary = LoadPeakConstants();
			float value;
			float num3 = (dictionary.TryGetValue("characterHeight", out value) ? value : 1.7f);
			float num4 = num3 / num * LegoScale.Value * result;
			float result3 = 180f;
			string path3 = Path.Combine(text, "rotation.txt");
			if (File.Exists(path3))
			{
				float.TryParse(File.ReadAllText(path3).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result3);
			}
			bool flag = Mathf.Abs(result3 - 180f) < 1f;
			bool flag2 = !flag;
			if (File.Exists(Path.Combine(text, "noflipz.txt")))
			{
				flag2 = false;
			}
			float result4 = 0f;
			string path4 = Path.Combine(text, "yaw_offset.txt");
			if (File.Exists(path4))
			{
				float.TryParse(File.ReadAllText(path4).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result4);
			}
			float num5 = val12.position.y - 0.9f;
			RaycastHit val13 = default(RaycastHit);
			if (Physics.Raycast(val12.position, Vector3.down, ref val13, 5f))
			{
				num5 = ((RaycastHit)(ref val13)).point.y;
			}
			GameObject val14 = new GameObject("LegoRoot");
			val14.transform.SetParent(val12, false);
			val14.transform.localScale = Vector3.one * num4;
			val14.transform.localRotation = Quaternion.Euler(0f, result3, 0f);
			val14.transform.position = new Vector3(val12.position.x, num5, val12.position.z);
			LegoStabilizer legoStabilizer = val14.AddComponent<LegoStabilizer>();
			legoStabilizer.hipBone = val12;
			legoStabilizer.baseYRotation = result3 + result4;
			legoStabilizer.heightOffset = 0f;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Scale={num4:F3} PeakH={num3:F3} ModelH={num:F2} CharScale={result:F2} GroundY={num5:F2}");
			Shader val15 = null;
			if ((Object)(object)mainRenderer != (Object)null && (Object)(object)((Renderer)mainRenderer).sharedMaterial != (Object)null)
			{
				val15 = ((Renderer)mainRenderer).sharedMaterial.shader;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Using game shader: " + ((Object)val15).name));
			}
			if ((Object)(object)val15 == (Object)null)
			{
				val15 = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Universal Render Pipeline/Simple Lit") ?? Shader.Find("Standard");
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Fallback shader: " + (((val15 != null) ? ((Object)val15).name : null) ?? "NULL")));
			}
			Material val16 = new Material(val15);
			Dictionary<string, Texture2D> texCache = _texCache;
			Dictionary<string, Material> matCache = _matCache;
			bool flag3 = File.Exists(Path.Combine(text, "arms_l.obj"));
			bool flag4 = File.Exists(Path.Combine(text, "legs_l.obj"));
			bool flag5 = File.Exists(Path.Combine(text, "chrome.txt"));
			_chromeMetallic = 1f;
			_chromeSmoothness = 0.9f;
			_hasChromeTint = false;
			_chromeEmission = 0f;
			if (flag5)
			{
				string[] array5 = File.ReadAllText(Path.Combine(text, "chrome.txt")).Trim().Split(new char[5] { ' ', ',', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				if (array5.Length >= 1)
				{
					float.TryParse(array5[0], NumberStyles.Float, invariantCulture, out _chromeMetallic);
				}
				if (array5.Length >= 2)
				{
					float.TryParse(array5[1], NumberStyles.Float, invariantCulture, out _chromeSmoothness);
				}
				if (array5.Length >= 5)
				{
					float result5 = 1f;
					float result6 = 1f;
					float result7 = 1f;
					float.TryParse(array5[2], NumberStyles.Float, invariantCulture, out result5);
					float.TryParse(array5[3], NumberStyles.Float, invariantCulture, out result6);
					float.TryParse(array5[4], NumberStyles.Float, invariantCulture, out result7);
					_chromeTint = new Color(result5, result6, result7, 1f);
					_hasChromeTint = true;
				}
				if (array5.Length >= 6)
				{
					float.TryParse(array5[5], NumberStyles.Float, invariantCulture, out _chromeEmission);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("  chrome: metallic={0} smoothness={1} tint={2} emission={3}", _chromeMetallic, _chromeSmoothness, _hasChromeTint ? ((object)Unsafe.As<Color, Color>(ref _chromeTint)/*cast due to .constrained prefix*/).ToString() : "none", _chromeEmission));
			}
			bool flag6 = File.Exists(Path.Combine(text, "cape.txt"));
			float num6 = num;
			float num7 = num6 * 0.714f;
			float value2;
			float num8 = num6 * (dictionary.TryGetValue("torsoY", out value2) ? value2 : 0.493f);
			float value3;
			float num9 = num6 * (dictionary.TryGetValue("armX", out value3) ? value3 : 0.148f) * ArmSpreadMult;
			float value4;
			float num10 = num6 * (dictionary.TryGetValue("armY", out value4) ? value4 : 0.591f);
			float value5;
			float num11 = num6 * (dictionary.TryGetValue("legX", out value5) ? value5 : 0.086f);
			float value6;
			float num12 = num6 * (dictionary.TryGetValue("legY", out value6) ? value6 : 0.222f);
			List<PartDef> list = new List<PartDef>();
			list.Add(new PartDef("torso", "Mid", new Vector3(0f, num8, 0f), 0.4f));
			list.Add(new PartDef("hips", null, Vector3.zero, 0f));
			list.Add(new PartDef("head", "Head", new Vector3(0f, num7, 0f), 0.5f));
			if (flag3)
			{
				if (flag)
				{
					list.Add(new PartDef("arms_l", "Arm_R", new Vector3(0f - num9, num10, 0f), 1f));
					list.Add(new PartDef("arms_r", "Arm_L", new Vector3(num9, num10, 0f), 1f));
				}
				else
				{
					list.Add(new PartDef("arms_l", "Arm_L", new Vector3(0f - num9, num10, 0f), 1f));
					list.Add(new PartDef("arms_r", "Arm_R", new Vector3(num9, num10, 0f), 1f));
				}
			}
			else
			{
				list.Add(new PartDef("arms", null, Vector3.zero, 0f));
			}
			if (flag4)
			{
				if (flag)
				{
					list.Add(new PartDef("legs_l", "Leg_R", new Vector3(0f - num11, num12, 0f), 0.7f));
					list.Add(new PartDef("legs_r", "Leg_L", new Vector3(num11, num12, 0f), 0.7f));
				}
				else
				{
					list.Add(new PartDef("legs_l", "Leg_L", new Vector3(0f - num11, num12, 0f), 0.7f));
					list.Add(new PartDef("legs_r", "Leg_R", new Vector3(num11, num12, 0f), 0.7f));
				}
			}
			else
			{
				list.Add(new PartDef("legs", null, Vector3.zero, 0f));
			}
			Dictionary<string, Transform> dictionary2 = new Dictionary<string, Transform>();
			if ((Object)(object)val4 != (Object)null)
			{
				dictionary2["Mid"] = val4;
			}
			if ((Object)(object)val5 != (Object)null)
			{
				dictionary2["Head"] = val5;
			}
			if ((Object)(object)val6 != (Object)null)
			{
				dictionary2["Arm_L"] = val6;
			}
			if ((Object)(object)val7 != (Object)null)
			{
				dictionary2["Arm_R"] = val7;
			}
			if ((Object)(object)val8 != (Object)null)
			{
				dictionary2["Leg_L"] = val8;
			}
			if ((Object)(object)val9 != (Object)null)
			{
				dictionary2["Leg_R"] = val9;
			}
			if ((Object)(object)val10 != (Object)null)
			{
				dictionary2["Hand_L"] = val10;
			}
			if ((Object)(object)val11 != (Object)null)
			{
				dictionary2["Hand_R"] = val11;
			}
			foreach (PartDef item in list)
			{
				string text6 = PartSourceDir(item.file, text);
				string path5 = Path.Combine(text6, item.file + ".obj");
				if (!File.Exists(path5))
				{
					continue;
				}
				ObjResult objResult = ObjLoader.Load(path5);
				if (objResult.Mesh.vertexCount == 0)
				{
					continue;
				}
				if (flag2)
				{
					Vector3[] vertices = objResult.Mesh.vertices;
					Vector3[] normals = objResult.Mesh.normals;
					for (int num13 = 0; num13 < vertices.Length; num13++)
					{
						vertices[num13] = new Vector3(vertices[num13].x, vertices[num13].y, 0f - vertices[num13].z);
					}
					for (int num14 = 0; num14 < normals.Length; num14++)
					{
						normals[num14] = new Vector3(normals[num14].x, normals[num14].y, 0f - normals[num14].z);
					}
					objResult.Mesh.vertices = vertices;
					objResult.Mesh.normals = normals;
					for (int num15 = 0; num15 < objResult.Mesh.subMeshCount; num15++)
					{
						int[] triangles = objResult.Mesh.GetTriangles(num15);
						for (int num16 = 0; num16 < triangles.Length; num16 += 3)
						{
							int num17 = triangles[num16];
							triangles[num16] = triangles[num16 + 2];
							triangles[num16 + 2] = num17;
						}
						objResult.Mesh.SetTriangles(triangles, num15);
					}
					objResult.Mesh.RecalculateBounds();
				}
				string text7 = item.file;
				string path6 = Path.Combine(text6, text7 + ".mtl");
				if (!File.Exists(path6))
				{
					string text8 = item.file.Split(new char[1] { '_' })[0];
					path6 = Path.Combine(text6, text8 + ".mtl");
					text7 = text8;
				}
				bool isChrome = flag5;
				string path7 = Path.Combine(text6, item.file + "_chrome.txt");
				if (File.Exists(path7))
				{
					isChrome = true;
					_chromeMetallic = 1f;
					_chromeSmoothness = 0.9f;
					string[] array6 = File.ReadAllText(path7).Trim().Split(new char[5] { ' ', ',', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
					CultureInfo invariantCulture2 = CultureInfo.InvariantCulture;
					if (array6.Length >= 1)
					{
						float.TryParse(array6[0], NumberStyles.Float, invariantCulture2, out _chromeMetallic);
					}
					if (array6.Length >= 2)
					{
						float.TryParse(array6[1], NumberStyles.Float, invariantCulture2, out _chromeSmoothness);
					}
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {item.file} chrome: metallic={_chromeMetallic} smoothness={_chromeSmoothness}");
				}
				_translucentAlpha = 1f;
				string path8 = Path.Combine(text6, item.file + "_translucent.txt");
				if (File.Exists(path8))
				{
					float.TryParse(File.ReadAllText(path8).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out _translucentAlpha);
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {item.file} translucent alpha={_translucentAlpha}");
				}
				Material[] materials = (Material[])((!File.Exists(path6)) ? ((Array)new Material[1]
				{
					new Material(val16)
				}) : ((Array)BuildMaterials(text6, text7, val16, texCache, matCache, objResult, isChrome)));
				if (item.boneName != null && dictionary2.ContainsKey(item.boneName))
				{
					Vector3 val17 = item.pivot;
					string path9 = Path.Combine(text6, item.file + "_offset.txt");
					if (File.Exists(path9))
					{
						string[] array7 = File.ReadAllText(path9).Trim().Split(new char[3] { ' ', ',', '\t' }, StringSplitOptions.RemoveEmptyEntries);
						CultureInfo invariantCulture3 = CultureInfo.InvariantCulture;
						float result8 = 0f;
						float result9 = 0f;
						float result10 = 0f;
						if (array7.Length >= 1)
						{
							float.TryParse(array7[0], NumberStyles.Float, invariantCulture3, out result8);
						}
						if (array7.Length >= 2)
						{
							float.TryParse(array7[1], NumberStyles.Float, invariantCulture3, out result9);
						}
						if (array7.Length >= 3)
						{
							float.TryParse(array7[2], NumberStyles.Float, invariantCulture3, out result10);
						}
						val17 += new Vector3(result8, result9, result10);
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {item.file} offset: ({result8},{result9},{result10})");
					}
					GameObject val18 = new GameObject("Lego_" + item.file + "_pivot");
					val18.transform.SetParent(val14.transform, false);
					val18.transform.localPosition = val17;
					val18.transform.localScale = Vector3.one;
					val18.transform.localRotation = Quaternion.identity;
					LegoBoneTracker legoBoneTracker = val18.AddComponent<LegoBoneTracker>();
					legoBoneTracker.targetBone = dictionary2[item.boneName];
					legoBoneTracker.influence = item.influence;
					legoBoneTracker.flipModel = flag;
					if (item.file == "head")
					{
						legoBoneTracker.isHead = true;
						legoBoneTracker.positionFollow = 0f;
					}
					if (item.file == "torso")
					{
						legoBoneTracker.isTorso = true;
						legoBoneTracker.characterTransform = val12;
						legoBoneTracker.positionFollow = 1f;
					}
					if (item.file.StartsWith("arms"))
					{
						legoBoneTracker.isArm = true;
						legoBoneTracker.characterTransform = val12;
						legoBoneTracker.positionFollow = 0f;
						bool flag7 = (flag ? item.file.Contains("_r") : item.file.Contains("_l"));
						legoBoneTracker.armSide = (flag7 ? 1f : (-1f));
						legoBoneTracker.isLeftArm = flag7;
						string key = ((item.boneName == "Arm_L") ? "Hand_L" : "Hand_R");
						if (dictionary2.ContainsKey(key))
						{
							legoBoneTracker.handBone = dictionary2[key];
						}
					}
					if (item.file.StartsWith("legs"))
					{
						legoBoneTracker.isLeg = true;
						legoBoneTracker.legSide = (item.file.Contains("_r") ? 1f : (-1f));
						legoBoneTracker.characterTransform = val12;
						legoBoneTracker.positionFollow = 0f;
					}
					GameObject val19 = new GameObject("Lego_" + item.file);
					val19.transform.SetParent(val18.transform, false);
					val19.transform.localPosition = -val17;
					val19.transform.localScale = Vector3.one;
					val19.transform.localRotation = Quaternion.identity;
					string path10 = Path.Combine(text, item.file + "_yaw.txt");
					if (File.Exists(path10) && float.TryParse(File.ReadAllText(path10).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result11))
					{
						Quaternion val20 = Quaternion.Euler(0f, result11, 0f);
						val19.transform.localRotation = val20 * val19.transform.localRotation;
						val19.transform.localPosition = val20 * val19.transform.localPosition;
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {item.file} yaw: {result11} deg");
					}
					string path11 = Path.Combine(text, item.file + "_lift.txt");
					if (File.Exists(path11) && float.TryParse(File.ReadAllText(path11).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result12))
					{
						Vector3 localPosition = val19.transform.localPosition;
						val19.transform.localPosition = new Vector3(localPosition.x, localPosition.y + result12, localPosition.z);
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {item.file} lift: {result12}");
					}
					val19.AddComponent<MeshFilter>().mesh = objResult.Mesh;
					MeshRenderer obj = val19.AddComponent<MeshRenderer>();
					((Renderer)obj).materials = materials;
					((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
					((Renderer)obj).receiveShadows = true;
					if (item.file == "head")
					{
						_headPivot = val18.transform;
						if (overrideDir == null)
						{
							HeadPivot = val18.transform;
						}
						_currentHeadMesh = val19;
						val19.AddComponent<LegoHeadFader>();
					}
					if (item.file == "torso" && flag6 && objResult.Mesh.subMeshCount >= 2)
					{
						ExtractClothCape(objResult.Mesh, materials, val18.transform, -item.pivot);
					}
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {item.file} -> {item.boneName} (pivot, {objResult.Mesh.vertexCount}v)");
				}
				else
				{
					GameObject val21 = new GameObject("Lego_" + item.file);
					val21.transform.SetParent(val14.transform, false);
					val21.transform.localPosition = Vector3.zero;
					val21.transform.localScale = Vector3.one;
					val21.transform.localRotation = Quaternion.identity;
					val21.AddComponent<MeshFilter>().mesh = objResult.Mesh;
					MeshRenderer obj2 = val21.AddComponent<MeshRenderer>();
					((Renderer)obj2).materials = materials;
					((Renderer)obj2).shadowCastingMode = (ShadowCastingMode)1;
					((Renderer)obj2).receiveShadows = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {item.file} -> root (static, {objResult.Mesh.vertexCount}v)");
				}
			}
			HideOriginalBody(character);
			_legoApplied = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"LEGO {_characters[_charIndex]} applied! ({list.Count} parts)");
			if (overrideDir == null && _characters[_charIndex] == "Batman")
			{
				TryGiveRescueClaw(character);
			}
		}

		private void TryGiveRescueClaw(Character character)
		{
			try
			{
				Type type = Type.GetType("ItemDatabase, Assembly-CSharp");
				if (type == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"ItemDatabase type not found");
					return;
				}
				Object[] array = Resources.FindObjectsOfTypeAll(type);
				if (array == null || array.Length == 0)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"No ItemDatabase");
					return;
				}
				Object obj = array[0];
				FieldInfo field = type.GetField("Objects", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Objects field not found");
					return;
				}
				if (!(field.GetValue(obj) is IList list))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Objects list is null");
					return;
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"ItemDatabase: {list.Count} items");
				object obj2 = null;
				int itemIdx = -1;
				for (int i = 0; i < list.Count; i++)
				{
					object obj3 = list[i];
					if (obj3 != null)
					{
						string text = obj3.ToString().ToLower();
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"  Item[{i}]: {obj3} ({obj3.GetType().Name})");
						if (text.Contains("rescue") || text.Contains("hook") || text.Contains("claw"))
						{
							obj2 = obj3;
							itemIdx = i;
							((BaseUnityPlugin)this).Logger.LogInfo((object)$"  >> RESCUE ITEM FOUND at index {i}: {obj3}");
						}
					}
				}
				if (obj2 != null)
				{
					GiveItemToPlayer(character, itemIdx, obj2);
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Rescue hook item not found in database");
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"RescueClaw error: {arg}");
			}
		}

		private void GiveItemToPlayer(Character character, int itemIdx, object itemDef)
		{
			try
			{
				Type type = ((object)character).GetType();
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					string text = methodInfo.Name.ToLower();
					if (text.Contains("item") || text.Contains("backpack") || text.Contains("equip"))
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("  Char." + methodInfo.Name + "(" + string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo p) => p.ParameterType.Name + " " + p.Name)) + ")"));
					}
				}
				Type type2 = itemDef.GetType();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("  Item type: " + type2.FullName));
				FieldInfo[] fields = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"    Item field: {fieldInfo.Name} = {fieldInfo.GetValue(itemDef)}");
				}
				PropertyInfo[] properties = type2.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo propertyInfo in properties)
				{
					try
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"    Item prop: {propertyInfo.Name} = {propertyInfo.GetValue(itemDef)}");
					}
					catch
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("    Item prop: " + propertyInfo.Name + " (error reading)"));
					}
				}
				MethodInfo method = type.GetMethod("PutItemInBackpack", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method != null)
				{
					ParameterInfo[] parameters = method.GetParameters();
					((BaseUnityPlugin)this).Logger.LogInfo((object)("  PutItemInBackpack(" + string.Join(", ", Array.ConvertAll(parameters, (ParameterInfo p) => p.ParameterType.Name)) + ")"));
					if (parameters.Length == 1)
					{
						method.Invoke(character, new object[1] { itemDef });
						((BaseUnityPlugin)this).Logger.LogInfo((object)"  >> Item given to backpack!");
						ColorItemGold(character);
					}
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"  PutItemInBackpack not found on Character");
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"GiveItem error: {arg}");
			}
		}

		private void ColorItemGold(Character character)
		{
			//IL_0095: 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)
			try
			{
				Renderer[] componentsInChildren = ((Component)character).GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					if (!((Object)((Component)val).gameObject).name.ToLower().Contains("hook") && !((Object)((Component)val).gameObject).name.ToLower().Contains("rescue") && !((Object)((Component)val).gameObject).name.ToLower().Contains("claw"))
					{
						continue;
					}
					Material[] materials = val.materials;
					foreach (Material val2 in materials)
					{
						val2.color = new Color(1f, 0.84f, 0f, 1f);
						if (val2.HasProperty("_BaseColor"))
						{
							val2.SetColor("_BaseColor", new Color(1f, 0.84f, 0f, 1f));
						}
						val2.SetFloat("_Metallic", 1f);
						val2.SetFloat("_Smoothness", 0.9f);
					}
					((BaseUnityPlugin)this).Logger.LogInfo((object)("  Colored gold: " + ((Object)((Component)val).gameObject).name));
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("ColorGold error: " + ex.Message));
			}
		}

		private void SwapHead(string sourceDir)
		{
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: 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_032a: Expected O, but got Unknown
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: 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_0368: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_headPivot == (Object)null)
			{
				return;
			}
			Transform val = _headPivot.Find("Lego_head");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			string path = Path.Combine(sourceDir, "head.obj");
			if (!File.Exists(path))
			{
				return;
			}
			ObjResult objResult = ObjLoader.Load(path);
			if (objResult.Mesh.vertexCount == 0)
			{
				return;
			}
			string path2 = Path.Combine(sourceDir, "noflipz.txt");
			float result = 180f;
			string path3 = Path.Combine(sourceDir, "rotation.txt");
			if (File.Exists(path3))
			{
				float.TryParse(File.ReadAllText(path3).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result);
			}
			if (!(Mathf.Abs(result - 180f) < 1f) && !File.Exists(path2))
			{
				Vector3[] vertices = objResult.Mesh.vertices;
				Vector3[] normals = objResult.Mesh.normals;
				for (int i = 0; i < vertices.Length; i++)
				{
					vertices[i] = new Vector3(vertices[i].x, vertices[i].y, 0f - vertices[i].z);
				}
				for (int j = 0; j < normals.Length; j++)
				{
					normals[j] = new Vector3(normals[j].x, normals[j].y, 0f - normals[j].z);
				}
				objResult.Mesh.vertices = vertices;
				objResult.Mesh.normals = normals;
				for (int k = 0; k < objResult.Mesh.subMeshCount; k++)
				{
					int[] triangles = objResult.Mesh.GetTriangles(k);
					for (int l = 0; l < triangles.Length; l += 3)
					{
						int num = triangles[l];
						triangles[l] = triangles[l + 2];
						triangles[l + 2] = num;
					}
					objResult.Mesh.SetTriangles(triangles, k);
				}
				objResult.Mesh.RecalculateBounds();
			}
			Material val2 = new Material(Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"));
			Dictionary<string, Texture2D> texCache = _texCache;
			Dictionary<string, Material> matCache = _matCache;
			Material[] materials = (Material[])((!File.Exists(Path.Combine(sourceDir, "head.mtl"))) ? ((Array)new Material[1]
			{
				new Material(val2)
			}) : ((Array)BuildMaterials(sourceDir, "head", val2, texCache, matCache, objResult)));
			float num2 = 4.06f;
			string path4 = Path.Combine(sourceDir, "head.obj");
			float num3 = 0f;
			string[] array = File.ReadAllLines(path4);
			foreach (string text in array)
			{
				if (text.StartsWith("v "))
				{
					string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
					if (array2.Length >= 3 && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && result2 > num3)
					{
						num3 = result2;
					}
				}
			}
			if (num3 > 1f)
			{
				num2 = num3;
			}
			Vector3 val3 = default(Vector3);
			((Vector3)(ref val3))..ctor(0f, num2 * 0.714f, 0f);
			GameObject val4 = new GameObject("Lego_head");
			val4.transform.SetParent(_headPivot, false);
			val4.transform.localPosition = -val3;
			val4.transform.localScale = Vector3.one;
			val4.transform.localRotation = Quaternion.identity;
			val4.AddComponent<MeshFilter>().mesh = objResult.Mesh;
			MeshRenderer obj = val4.AddComponent<MeshRenderer>();
			((Renderer)obj).materials = materials;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)obj).receiveShadows = true;
			val4.AddComponent<LegoHeadFader>();
			_currentHeadMesh = val4;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Head swapped from {Path.GetFileName(sourceDir)} ({objResult.Mesh.vertexCount}v)");
		}

		private void ApplyAccessory(string objPath)
		{
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Expected O, but got Unknown
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Expected O, but got Unknown
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			RemoveAccessory();
			if ((Object)(object)_headPivot == (Object)null)
			{
				return;
			}
			string directoryName = Path.GetDirectoryName(objPath);
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(objPath);
			ObjResult objResult = ObjLoader.Load(objPath);
			if (objResult.Mesh.vertexCount == 0)
			{
				return;
			}
			string path = Path.Combine(directoryName, "noflipz.txt");
			float result = 180f;
			string path2 = Path.Combine(directoryName, "rotation.txt");
			if (File.Exists(path2))
			{
				float.TryParse(File.ReadAllText(path2).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result);
			}
			if (!(Mathf.Abs(result - 180f) < 1f) && !File.Exists(path))
			{
				Vector3[] vertices = objResult.Mesh.vertices;
				Vector3[] normals = objResult.Mesh.normals;
				for (int i = 0; i < vertices.Length; i++)
				{
					vertices[i] = new Vector3(vertices[i].x, vertices[i].y, 0f - vertices[i].z);
				}
				for (int j = 0; j < normals.Length; j++)
				{
					normals[j] = new Vector3(normals[j].x, normals[j].y, 0f - normals[j].z);
				}
				objResult.Mesh.vertices = vertices;
				objResult.Mesh.normals = normals;
				for (int k = 0; k < objResult.Mesh.subMeshCount; k++)
				{
					int[] triangles = objResult.Mesh.GetTriangles(k);
					for (int l = 0; l < triangles.Length; l += 3)
					{
						int num = triangles[l];
						triangles[l] = triangles[l + 2];
						triangles[l + 2] = num;
					}
					objResult.Mesh.SetTriangles(triangles, k);
				}
				objResult.Mesh.RecalculateBounds();
			}
			Material val = new Material(Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"));
			Dictionary<string, Texture2D> texCache = _texCache;
			Dictionary<string, Material> matCache = _matCache;
			Material[] materials = (Material[])((!File.Exists(Path.Combine(directoryName, fileNameWithoutExtension + ".mtl"))) ? ((Array)new Material[1]
			{
				new Material(val)
			}) : ((Array)BuildMaterials(directoryName, fileNameWithoutExtension, val, texCache, matCache, objResult)));
			float num2 = 4.06f;
			string path3 = Path.Combine(directoryName, "head.obj");
			if (File.Exists(path3))
			{
				float num3 = 0f;
				string[] array = File.ReadAllLines(path3);
				foreach (string text in array)
				{
					if (text.StartsWith("v "))
					{
						string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
						if (array2.Length >= 3 && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && result2 > num3)
						{
							num3 = result2;
						}
					}
				}
				if (num3 > 1f)
				{
					num2 = num3;
				}
			}
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0f, num2 * 0.714f, 0f);
			GameObject val3 = new GameObject("Lego_accessory_" + fileNameWithoutExtension);
			val3.transform.SetParent(_headPivot, false);
			val3.transform.localPosition = -val2;
			val3.transform.localScale = Vector3.one;
			val3.transform.localRotation = Quaternion.identity;
			val3.AddComponent<MeshFilter>().mesh = objResult.Mesh;
			MeshRenderer obj = val3.AddComponent<MeshRenderer>();
			((Renderer)obj).materials = materials;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)obj).receiveShadows = true;
			val3.AddComponent<LegoHeadFader>();
			_currentAccessory = val3;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Accessory: {fileNameWithoutExtension} from {Path.GetFileName(directoryName)} ({objResult.Mesh.vertexCount}v)");
		}

		private void RemoveAccessory()
		{
			if ((Object)(object)_currentAccessory != (Object)null)
			{
				Object.Destroy((Object)(object)_currentAccessory);
				_currentAccessory = null;
			}
		}

		private void CycleHandColor()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_016a: Unknown result type (might be due to invalid IL or missing references)
			_handColorIndex = (_handColorIndex + 1) % HandColors.Length;
			Color val = HandColors[_handColorIndex];
			string[] array = new string[9] { "Yellow", "Gold", "Brown", "Dark Brown", "Peach", "Black", "White", "Red", "Green" };
			string text = ((_handColorIndex < array.Length) ? array[_handColorIndex] : $"Color {_handColorIndex}");
			Transform[] array2 = Object.FindObjectsByType<Transform>((FindObjectsSortMode)0);
			foreach (Transform val2 in array2)
			{
				if ((Object)(object)val2 == (Object)null || ((Object)((Component)val2).gameObject).name != "LegoRoot")
				{
					continue;
				}
				Renderer[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val3 in componentsInChildren)
				{
					if (!((Object)((Component)val3).gameObject).name.ToLower().Contains("arm"))
					{
						continue;
					}
					Material[] materials = val3.materials;
					foreach (Material val4 in materials)
					{
						val4.mainTexture = null;
						if (val4.HasProperty("_BaseMap"))
						{
							val4.SetTexture("_BaseMap", (Texture)null);
						}
						val4.color = val;
						if (val4.HasProperty("_BaseColor"))
						{
							val4.SetColor("_BaseColor", val);
						}
					}
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Hand color -> " + text));
		}

		private void ExtractClothCape(Mesh torsoMesh, Material[] materials, Transform parent, Vector3 offset)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Expected O, but got Unknown
			//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_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: 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_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Expected O, but got Unknown
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			if (torsoMesh.subMeshCount < 2)
			{
				return;
			}
			int[] triangles = torsoMesh.GetTriangles(1);
			if (triangles.Length == 0)
			{
				return;
			}
			Vector3[] vertices = torsoMesh.vertices;
			Vector3[] normals = torsoMesh.normals;
			Vector2[] uv = torsoMesh.uv;
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			List<Vector3> list = new List<Vector3>();
			List<Vector3> list2 = new List<Vector3>();
			List<Vector2> list3 = new List<Vector2>();
			List<int> list4 = new List<int>();
			foreach (int num in triangles)
			{
				if (!dictionary.ContainsKey(num))
				{
					dictionary[num] = list.Count;
					list.Add(vertices[num]);
					list2.Add((num < normals.Length) ? normals[num] : Vector3.up);
					list3.Add((num < uv.Length) ? uv[num] : Vector2.zero);
				}
				list4.Add(dictionary[num]);
			}
			Dictionary<long, int> cache = new Dictionary<long, int>();
			List<int> list5 = new List<int>();
			for (int j = 0; j < list4.Count; j += 3)
			{
				int num2 = list4[j];
				int num3 = list4[j + 1];
				int num4 = list4[j + 2];
				int orCreateMidpoint = GetOrCreateMidpoint(num2, num3, list, list2, list3, cache);
				int orCreateMidpoint2 = GetOrCreateMidpoint(num3, num4, list, list2, list3, cache);
				int orCreateMidpoint3 = GetOrCreateMidpoint(num4, num2, list, list2, list3, cache);
				list5.AddRange(new int[12]
				{
					num2, orCreateMidpoint, orCreateMidpoint3, orCreateMidpoint, num3, orCreateMidpoint2, orCreateMidpoint3, orCreateMidpoint2, num4, orCreateMidpoint,
					orCreateMidpoint2, orCreateMidpoint3
				});
			}
			list4 = list5;
			Mesh val = new Mesh();
			val.vertices = list.ToArray();
			val.normals = list2.ToArray();
			val.uv = list3.ToArray();
			val.triangles = list4.ToArray();
			val.RecalculateBounds();
			val.RecalculateNormals();
			GameObject val2 = new GameObject("Lego_cape_cloth");
			val2.transform.SetParent(parent, false);
			val2.transform.localPosition = offset + new Vector3(0f, -0.15f, -0.02f);
			val2.transform.localScale = new Vector3(1.03f, 1.02f, 1.03f);
			val2.transform.localRotation = Quaternion.identity;
			val2.AddComponent<MeshFilter>().mesh = val;
			Material val3 = ((materials.Length > 1) ? new Material(materials[1]) : new Material(materials[0]));
			Color val4 = default(Color);
			((Color)(ref val4))..ctor(0.35f, 0.35f, 0.38f, 1f);
			val3.SetTexture("_BumpMap", (Texture)null);
			val3.SetTexture("_DetailAlbedoMap", (Texture)null);
			val3.SetTexture("_DetailNormalMap", (Texture)null);
			val3.DisableKeyword("_NORMALMAP");
			val3.DisableKeyword("_DETAIL_MULX2");
			val3.SetColor("_BaseColor", val4);
			val3.color = val4;
			val3.SetFloat("_Smoothness", 0.15f);
			val3.SetFloat("_Metallic", 0f);
			val3.renderQueue = 2001;
			MeshRenderer obj = val2.AddComponent<MeshRenderer>();
			((Renderer)obj).material = val3;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)obj).receiveShadows = true;
			torsoMesh.SetTriangles(new int[0], 1);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"  Cape: {val.vertexCount}v, static (no physics)");
		}

		private int GetOrCreateMidpoint(int a, int b, List<Vector3> verts, List<Vector3> norms, List<Vector2> uvs, Dictionary<long, int> cache)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			long key = ((a < b) ? (((long)a << 32) | (uint)b) : (((long)b << 32) | (uint)a));
			if (cache.TryGetValue(key, out var value))
			{
				return value;
			}
			value = verts.Count;
			verts.Add((verts[a] + verts[b]) * 0.5f);
			Vector3 val = norms[a] + norms[b];
			norms.Add(((Vector3)(ref val)).normalized);
			uvs.Add((uvs[a] + uvs[b]) * 0.5f);
			cache[key] = value;
			return value;
		}

		private void DumpCharacterMesh(Character character)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: 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_0431: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: 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_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04df: Unknown result type (might be due to invalid IL or missing references)
			//IL_04eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0510: Unknown result type (might be due to invalid IL or missing references)
			//IL_051f: Unknown result type (might be due to invalid IL or missing references)
			//IL_052e: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Unknown result type (might be due to invalid IL or missing references)
			//IL_055b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0567: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(_pluginDir, "MeshDump");
			Directory.CreateDirectory(text);
			SkinnedMeshRenderer[] componentsInChildren = ((Component)character).GetComponentsInChildren<SkinnedMeshRenderer>(true);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"=== MESH DUMP: {componentsInChildren.Length} SkinnedMeshRenderers ===");
			HashSet<Transform> hashSet = new HashSet<Transform>();
			int num = 0;
			SkinnedMeshRenderer[] array = componentsInChildren;
			foreach (SkinnedMeshRenderer val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				Mesh val2 = new Mesh();
				val.BakeMesh(val2);
				string arg = ((Object)((Component)val).gameObject).name.Replace(" ", "_");
				using (StreamWriter streamWriter = new StreamWriter(Path.Combine(text, $"{arg}_{num}.obj")))
				{
					streamWriter.WriteLine("# PEAK Mesh Dump: " + ((Object)((Component)val).gameObject).name);
					streamWriter.WriteLine($"# Vertices: {val2.vertexCount} Triangles: {val2.triangles.Length / 3}");
					Vector3[] vertices = val2.vertices;
					Vector3[] normals = val2.normals;
					Vector2[] uv = val2.uv;
					Matrix4x4 localToWorldMatrix = ((Component)val).transform.localToWorldMatrix;
					for (int j = 0; j < vertices.Length; j++)
					{
						Vector3 val3 = ((Matrix4x4)(ref localToWorldMatrix)).MultiplyPoint3x4(vertices[j]);
						streamWriter.WriteLine($"v {val3.x:F6} {val3.y:F6} {val3.z:F6}");
					}
					for (int k = 0; k < uv.Length; k++)
					{
						streamWriter.WriteLine($"vt {uv[k].x:F6} {uv[k].y:F6}");
					}
					for (int l = 0; l < normals.Length; l++)
					{
						Vector3 val4 = ((Matrix4x4)(ref localToWorldMatrix)).MultiplyVector(normals[l]);
						Vector3 normalized = ((Vector3)(ref val4)).normalized;
						streamWriter.WriteLine($"vn {normalized.x:F6} {normalized.y:F6} {normalized.z:F6}");
					}
					int[] triangles = val2.triangles;
					for (int m = 0; m < triangles.Length; m += 3)
					{
						int num2 = triangles[m] + 1;
						int num3 = triangles[m + 1] + 1;
						int num4 = triangles[m + 2] + 1;
						streamWriter.WriteLine($"f {num2}/{num2}/{num2} {num3}/{num3}/{num3} {num4}/{num4}/{num4}");
					}
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"  Dumped: {arg}_{num}.obj ({val2.vertexCount}v)");
				if (val.bones != null)
				{
					Transform[] bones = val.bones;
					foreach (Transform val5 in bones)
					{
						if ((Object)(object)val5 != (Object)null)
						{
							hashSet.Add(val5);
						}
					}
				}
				Object.Destroy((Object)(object)val2);
				num++;
			}
			using (StreamWriter streamWriter2 = new StreamWriter(Path.Combine(text, "skeleton.json")))
			{
				streamWriter2.WriteLine("{");
				streamWriter2.WriteLine("  \"bones\": [");
				List<Transform> list = new List<Transform>(hashSet);
				List<Transform> list2 = new List<Transform>();
				foreach (Transform item in list)
				{
					Transform val6 = item;
					while ((Object)(object)val6 != (Object)null && !list2.Contains(val6))
					{
						list2.Add(val6);
						if ((Object)(object)val6 == (Object)(object)((Component)character).transform)
						{
							break;
						}
						val6 = val6.parent;
					}
				}
				for (int num5 = 0; num5 < list2.Count; num5++)
				{
					Transform val7 = list2[num5];
					Vector3 position = val7.position;
					Vector3 localScale = val7.localScale;
					Quaternion localRotation = val7.localRotation;
					string text2 = (((Object)(object)val7.parent != (Object)null && list2.Contains(val7.parent)) ? ((Object)val7.parent).name : "");
					string text3 = ((num5 < list2.Count - 1) ? "," : "");
					streamWriter2.WriteLine("    {");
					streamWriter2.WriteLine("      \"name\": \"" + ((Object)val7).name + "\",");
					streamWriter2.WriteLine("      \"parent\": \"" + text2 + "\",");
					streamWriter2.WriteLine($"      \"world_pos\": [{position.x:F6}, {position.y:F6}, {position.z:F6}],");
					streamWriter2.WriteLine($"      \"local_rot\": [{localRotation.x:F6}, {localRotation.y:F6}, {localRotation.z:F6}, {localRotation.w:F6}],");
					streamWriter2.WriteLine($"      \"local_scale\": [{localScale.x:F6}, {localScale.y:F6}, {localScale.z:F6}]");
					streamWriter2.WriteLine("    }" + text3);
				}
				streamWriter2.WriteLine("  ]");
				streamWriter2.WriteLine("}");
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Skeleton dumped: {componentsInChildren.Length} meshes, {hashSet.Count} bones -> {text}");
		}

		private void DumpBoneQuaternions(Character character)
		{
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			SkinnedMeshRenderer mainRenderer = character.refs.mainRenderer;
			if (((mainRenderer != null) ? mainRenderer.bones : null) == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"No bones found");
				return;
			}
			string text = Path.Combine(_pluginDir, "bone_quaternions.txt");
			using (StreamWriter streamWriter = new StreamWriter(text))
			{
				streamWriter.WriteLine($"PEAK Bone Quaternions - {DateTime.Now}");
	

BepInEx/plugins/Furter-LegoWorld/Furter.LegoWorld.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Furter.LegoWorld")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+5a5016aeeba2c65ae3ed79d54956c58090639b1c")]
[assembly: AssemblyProduct("Furter.LegoWorld")]
[assembly: AssemblyTitle("LegoWorld")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace LegoWorld
{
	public class LegoCharacterParts
	{
		public GameObject? Head;

		public GameObject? Torso;

		public GameObject? ArmR;

		public GameObject? ArmL;

		public GameObject? LegR;

		public GameObject? LegL;

		public GameObject? Cape;

		public GameObject? Hat;

		public GameObject? Helmet;

		public GameObject? Hair;

		public float TotalHeight;

		public static readonly string[] AllPartTypes = new string[9] { "head", "torso", "armR", "armL", "legR", "legL", "hat", "helmet", "hair" };

		public static readonly string[] BoneNames = new string[9] { "Head", "Torso", "Arm_R", "Arm_L", "Hip_R", "Hip_L", "Head", "Head", "Head" };

		public GameObject? GetPart(string partType)
		{
			return (GameObject?)(partType switch
			{
				"head" => Head, 
				"torso" => Torso, 
				"armR" => ArmR, 
				"armL" => ArmL, 
				"legR" => LegR, 
				"legL" => LegL, 
				"cape" => Cape, 
				"hat" => Hat, 
				"helmet" => Helmet, 
				"hair" => Hair, 
				_ => null, 
			});
		}
	}
	public class LegoLoadout
	{
		public string? Head;

		public string? Torso;

		public string? Arms;

		public string? Legs;

		public string? Hat;

		public string? Helmet;

		public string? Hair;

		private static ConfigEntry<string>? _cfgHead;

		private static ConfigEntry<string>? _cfgTorso;

		private static ConfigEntry<string>? _cfgArms;

		private static ConfigEntry<string>? _cfgLegs;

		private static ConfigEntry<string>? _cfgHat;

		private static ConfigEntry<string>? _cfgHelmet;

		private static ConfigEntry<string>? _cfgHair;

		public static LegoLoadout Current { get; private set; } = new LegoLoadout();

		public static void BindConfig(ConfigFile config)
		{
			_cfgHead = config.Bind<string>("Loadout", "Head", "", "LEGO character for head");
			_cfgTorso = config.Bind<string>("Loadout", "Torso", "", "LEGO character for torso");
			_cfgArms = config.Bind<string>("Loadout", "Arms", "", "LEGO character for both arms");
			_cfgLegs = config.Bind<string>("Loadout", "Legs", "", "LEGO character for both legs");
			_cfgHat = config.Bind<string>("Loadout", "Hat", "", "LEGO character for hat (empty = none)");
			_cfgHelmet = config.Bind<string>("Loadout", "Helmet", "", "LEGO character for helmet (empty = none)");
			_cfgHair = config.Bind<string>("Loadout", "Hair", "", "LEGO character for hair (empty = none)");
			Load();
		}

		public static void Load()
		{
			Current = new LegoLoadout
			{
				Head = NullIfEmpty(_cfgHead?.Value),
				Torso = NullIfEmpty(_cfgTorso?.Value),
				Arms = NullIfEmpty(_cfgArms?.Value),
				Legs = NullIfEmpty(_cfgLegs?.Value),
				Hat = NullIfEmpty(_cfgHat?.Value),
				Helmet = NullIfEmpty(_cfgHelmet?.Value),
				Hair = NullIfEmpty(_cfgHair?.Value)
			};
		}

		public static void Save()
		{
			if (_cfgHead != null)
			{
				_cfgHead.Value = Current.Head ?? "";
			}
			if (_cfgTorso != null)
			{
				_cfgTorso.Value = Current.Torso ?? "";
			}
			if (_cfgArms != null)
			{
				_cfgArms.Value = Current.Arms ?? "";
			}
			if (_cfgLegs != null)
			{
				_cfgLegs.Value = Current.Legs ?? "";
			}
			if (_cfgHat != null)
			{
				_cfgHat.Value = Current.Hat ?? "";
			}
			if (_cfgHelmet != null)
			{
				_cfgHelmet.Value = Current.Helmet ?? "";
			}
			if (_cfgHair != null)
			{
				_cfgHair.Value = Current.Hair ?? "";
			}
		}

		public string? GetPartCharacter(string partType)
		{
			return partType switch
			{
				"head" => Head, 
				"torso" => Torso, 
				"armR" => Arms, 
				"armL" => Arms, 
				"legR" => Legs, 
				"legL" => Legs, 
				"hat" => Hat, 
				"helmet" => Helmet, 
				"hair" => Hair, 
				_ => null, 
			};
		}

		public void SetCategory(string category, string? charName)
		{
			if (category == null)
			{
				return;
			}
			switch (category.Length)
			{
			case 4:
				switch (category[2])
				{
				case 'm':
					if (category == "arms")
					{
						Arms = charName;
					}
					break;
				case 'g':
					if (category == "legs")
					{
						Legs = charName;
					}
					break;
				case 't':
					if (category == "hats")
					{
						Hat = charName;
					}
					break;
				case 'i':
					if (category == "hair")
					{
						Hair = charName;
					}
					break;
				}
				break;
			case 5:
				if (category == "heads")
				{
					Head = charName;
				}
				break;
			case 6:
				if (category == "torsos")
				{
					Torso = charName;
				}
				break;
			case 7:
				if (category == "helmets")
				{
					Helmet = charName;
				}
				break;
			}
		}

		private static string? NullIfEmpty(string? s)
		{
			if (!string.IsNullOrWhiteSpace(s))
			{
				return s;
			}
			return null;
		}
	}
	[HarmonyPatch]
	public static class LegoEnvironmentPatch
	{
		private static readonly HashSet<int> ReplacedTrees = new HashSet<int>();

		private static readonly HashSet<int> ReplacedBridges = new HashSet<int>();

		[HarmonyPatch(typeof(SpawnConnectingBridge), "CheckCondition")]
		[HarmonyPostfix]
		public static void OnTreeSpawnCheck(SpawnConnectingBridge __instance)
		{
		}

		[HarmonyPatch(typeof(BreakableBridge), "Awake")]
		[HarmonyPostfix]
		public static void OnBridgeAwake(BreakableBridge __instance)
		{
			if (Plugin.ReplaceBridges.Value && !((Object)(object)Plugin.LegoBridgePrefab == (Object)null))
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!ReplacedBridges.Contains(instanceID))
				{
					ReplacedBridges.Add(instanceID);
					ReplaceVisuals(((Component)__instance).gameObject, Plugin.LegoBridgePrefab);
					Plugin.Log.LogInfo((object)("Replaced bridge: " + ((Object)((Component)__instance).gameObject).name));
				}
			}
		}

		private static void ReplaceWithLegoModel(GameObject target, GameObject legoPrefab)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_00e7: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer[] componentsInChildren = target.GetComponentsInChildren<MeshRenderer>();
			SkinnedMeshRenderer[] componentsInChildren2 = target.GetComponentsInChildren<SkinnedMeshRenderer>();
			Bounds val = default(Bounds);
			bool flag = false;
			MeshRenderer[] array = componentsInChildren;
			foreach (MeshRenderer val2 in array)
			{
				if (!flag)
				{
					val = ((Renderer)val2).bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref val)).Encapsulate(((Renderer)val2).bounds);
				}
				((Renderer)val2).enabled = false;
			}
			SkinnedMeshRenderer[] array2 = componentsInChildren2;
			foreach (SkinnedMeshRenderer val3 in array2)
			{
				if (!flag)
				{
					val = ((Renderer)val3).bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref val)).Encapsulate(((Renderer)val3).bounds);
				}
				((Renderer)val3).enabled = false;
			}
			GameObject val4 = Object.Instantiate<GameObject>(legoPrefab, target.transform);
			val4.transform.localPosition = Vector3.zero;
			val4.transform.localRotation = Quaternion.identity;
			if (!flag)
			{
				return;
			}
			Renderer[] componentsInChildren3 = val4.GetComponentsInChildren<Renderer>();
			if (componentsInChildren3.Length != 0)
			{
				Bounds bounds = componentsInChildren3[0].bounds;
				Renderer[] array3 = componentsInChildren3;
				foreach (Renderer val5 in array3)
				{
					((Bounds)(ref bounds)).Encapsulate(val5.bounds);
				}
				float num = ((Bounds)(ref val)).size.y / Mathf.Max(((Bounds)(ref bounds)).size.y, 0.001f);
				float num2 = ((Bounds)(ref val)).size.x / Mathf.Max(((Bounds)(ref bounds)).size.x, 0.001f);
				float num3 = Mathf.Min(num2, num);
				val4.transform.localScale = Vector3.one * num3;
			}
		}

		private static void ReplaceVisuals(GameObject target, GameObject legoPrefab)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			Transform val = target.transform.Find("fullMesh");
			Bounds val2 = default(Bounds);
			bool flag = false;
			if ((Object)(object)val != (Object)null)
			{
				Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>();
				Renderer[] array = componentsInChildren;
				foreach (Renderer val3 in array)
				{
					if (!flag)
					{
						val2 = val3.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref val2)).Encapsulate(val3.bounds);
					}
					val3.enabled = false;
				}
			}
			else
			{
				MeshRenderer[] componentsInChildren2 = target.GetComponentsInChildren<MeshRenderer>();
				MeshRenderer[] array2 = componentsInChildren2;
				foreach (MeshRenderer val4 in array2)
				{
					if (!flag)
					{
						val2 = ((Renderer)val4).bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref val2)).Encapsulate(((Renderer)val4).bounds);
					}
					((Renderer)val4).enabled = false;
				}
			}
			GameObject val5 = Object.Instantiate<GameObject>(legoPrefab, target.transform);
			val5.transform.localPosition = Vector3.zero;
			val5.transform.localRotation = Quaternion.identity;
			if (!flag)
			{
				return;
			}
			Renderer[] componentsInChildren3 = val5.GetComponentsInChildren<Renderer>();
			if (componentsInChildren3.Length != 0)
			{
				Bounds bounds = componentsInChildren3[0].bounds;
				Renderer[] array3 = componentsInChildren3;
				foreach (Renderer val6 in array3)
				{
					((Bounds)(ref bounds)).Encapsulate(val6.bounds);
				}
				float num = ((Bounds)(ref val2)).size.x / Mathf.Max(((Bounds)(ref bounds)).size.x, 0.001f);
				val5.transform.localScale = Vector3.one * num;
			}
		}
	}
	public static class LegoHeadCulling
	{
		public const int CulledLayer = 31;

		private static bool _mainCameraPatched;

		private static bool _loggedCameraInfo;

		public static void SetPartLayer(GameObject part)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			part.layer = 31;
			foreach (Transform item in part.transform)
			{
				Transform val = item;
				((Component)val).gameObject.layer = 31;
			}
			PatchMainCamera();
		}

		public static bool IsLocalPlayer(Transform characterRoot)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return false;
			}
			if (((Component)main).transform.IsChildOf(characterRoot))
			{
				return true;
			}
			float num = Vector3.Distance(((Component)main).transform.position, characterRoot.position);
			if (!_loggedCameraInfo)
			{
				_loggedCameraInfo = true;
				ManualLogSource log = Plugin.Log;
				string[] obj = new string[7]
				{
					"Camera debug: cam=",
					((Object)main).name,
					" parent=",
					null,
					null,
					null,
					null
				};
				Transform parent = ((Component)main).transform.parent;
				obj[3] = ((parent != null) ? ((Object)parent).name : null) ?? "NULL";
				obj[4] = " ";
				Transform root = ((Component)main).transform.root;
				obj[5] = string.Format("root={0} camPos={1} ", ((root != null) ? ((Object)root).name : null) ?? "NULL", ((Component)main).transform.position);
				obj[6] = $"charPos={characterRoot.position} dist={num:F2}";
				log.LogInfo((object)string.Concat(obj));
				Transform root2 = characterRoot.root;
				Plugin.Log.LogInfo((object)("Character root object: " + ((Object)root2).name));
			}
			return num < 2f;
		}

		private static void PatchMainCamera()
		{
			if (!_mainCameraPatched)
			{
				Camera main = Camera.main;
				if (!((Object)(object)main == (Object)null))
				{
					main.cullingMask &= 0x7FFFFFFF;
					_mainCameraPatched = true;
					Plugin.Log.LogInfo((object)$"First-person culling: main camera excludes layer {31}");
				}
			}
		}

		public static void TryPatchCamera()
		{
			if (!_mainCameraPatched)
			{
				PatchMainCamera();
			}
		}
	}
	public static class LegoMinikitFactory
	{
		public static GameObject Build()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("LegoMinikit");
			GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)2);
			((Object)val2).name = "MinikitBody";
			Object.Destroy((Object)(object)val2.GetComponent<Collider>());
			val2.transform.SetParent(val.transform, false);
			val2.transform.localScale = new Vector3(0.6f, 1f, 0.6f);
			Material sharedMaterial = MakeLit(new Color(0.62f, 0.62f, 0.66f), 0.35f);
			((Renderer)val2.GetComponent<MeshRenderer>()).sharedMaterial = sharedMaterial;
			MeshRenderer green = MakeLight(val.transform, new Vector3(0.42f, 0.7f, 0f), Color.green);
			MeshRenderer red = MakeLight(val.transform, new Vector3(-0.42f, 0.7f, 0f), Color.red);
			MinikitBlink minikitBlink = val.AddComponent<MinikitBlink>();
			minikitBlink.green = green;
			minikitBlink.red = red;
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			return val;
		}

		private static MeshRenderer MakeLight(Transform parent, Vector3 localPos, Color c)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)val).name = "MinikitLight";
			Object.Destroy((Object)(object)val.GetComponent<Collider>());
			val.transform.SetParent(parent, false);
			val.transform.localPosition = localPos;
			val.transform.localScale = Vector3.one * 0.28f;
			Material val2 = MakeLit(c, 0.6f);
			val2.EnableKeyword("_EMISSION");
			val2.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)1;
			val2.SetColor("_EmissionColor", c);
			MeshRenderer component = val.GetComponent<MeshRenderer>();
			((Renderer)component).sharedMaterial = val2;
			return component;
		}

		private static Material MakeLit(Color c, float smooth)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
			Material val2 = new Material(val);
			if (val2.HasProperty("_BaseColor"))
			{
				val2.SetColor("_BaseColor", c);
			}
			val2.color = c;
			if (val2.HasProperty("_Smoothness"))
			{
				val2.SetFloat("_Smoothness", smooth);
			}
			if (val2.HasProperty("_Metallic"))
			{
				val2.SetFloat("_Metallic", 0f);
			}
			return val2;
		}
	}
	public class MinikitBlink : MonoBehaviour
	{
		public MeshRenderer green;

		public MeshRenderer red;

		private Material _g;

		private Material _r;

		private float _t;

		private void Start()
		{
			if ((Object)(object)green != (Object)null)
			{
				_g = ((Renderer)green).material;
			}
			if ((Object)(object)red != (Object)null)
			{
				_r = ((Renderer)red).material;
			}
		}

		private void Update()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			_t += Time.deltaTime * 4f;
			float num = Mathf.Sin(_t) * 0.5f + 0.5f;
			float num2 = 1f - num;
			if ((Object)(object)_g != (Object)null)
			{
				_g.SetColor("_EmissionColor", Color.green * (0.15f + num * 2.5f));
			}
			if ((Object)(object)_r != (Object)null)
			{
				_r.SetColor("_EmissionColor", Color.red * (0.15f + num2 * 2.5f));
			}
		}
	}
	public static class LegoModelLoader
	{
		public static void LoadFromFBXFolder(string folderPath)
		{
			if (!Directory.Exists(folderPath))
			{
				Plugin.Log.LogWarning((object)("FBX folder not found: " + folderPath));
				return;
			}
			string[] files = Directory.GetFiles(folderPath, "*.fbx");
			Plugin.Log.LogInfo((object)$"Found {files.Length} FBX files in {folderPath}");
			string[] array = files;
			foreach (string path in array)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
				if (fileNameWithoutExtension == "LegoTree")
				{
					GameObject val = LoadFBXAsPrefab(path, fileNameWithoutExtension);
					if ((Object)(object)val != (Object)null)
					{
						Plugin.LegoTreePrefab = val;
					}
				}
				else if (fileNameWithoutExtension == "LegoBridge")
				{
					GameObject val2 = LoadFBXAsPrefab(path, fileNameWithoutExtension);
					if ((Object)(object)val2 != (Object)null)
					{
						Plugin.LegoBridgePrefab = val2;
					}
				}
				else
				{
					GameObject val3 = LoadFBXAsPrefab(path, fileNameWithoutExtension);
					if ((Object)(object)val3 != (Object)null)
					{
						Plugin.LegoCharacterPrefabs[fileNameWithoutExtension] = val3;
					}
				}
			}
		}

		private static GameObject? LoadFBXAsPrefab(string path, string name)
		{
			try
			{
				byte[] array = File.ReadAllBytes(path);
				AssetBundle val = AssetBundle.LoadFromMemory(array);
				if ((Object)(object)val != (Object)null)
				{
					GameObject val2 = val.LoadAsset<GameObject>(name);
					if ((Object)(object)val2 != (Object)null)
					{
						Plugin.Log.LogInfo((object)("Loaded model: " + name));
						return val2;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Cannot load FBX directly: " + name + " (" + ex.Message + ")"));
			}
			return CreatePrimitiveStandin(name);
		}

		private static GameObject CreatePrimitiveStandin(string name)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)1);
			((Object)val).name = name;
			Object.DontDestroyOnLoad((Object)(object)val);
			val.SetActive(false);
			Renderer component = val.GetComponent<Renderer>();
			if ((Object)(object)component != (Object)null)
			{
				Material val2 = new Material(Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"));
				int hashCode = name.GetHashCode();
				val2.color = new Color((float)((hashCode >> 16) & 0xFF) / 255f, (float)((hashCode >> 8) & 0xFF) / 255f, (float)(hashCode & 0xFF) / 255f);
				component.material = val2;
			}
			Plugin.Log.LogInfo((object)("Created standin for: " + name + " (FBX direct load not supported at runtime)"));
			return val;
		}
	}
	[HarmonyPatch]
	public static class LegoOutfitPatch
	{
		private static readonly Dictionary<CharacterCustomization, GameObject[]> SpawnedLegoParts = new Dictionary<CharacterCustomization, GameObject[]>();

		private static readonly Dictionary<PlayerCustomizationDummy, GameObject[]> SpawnedDummyParts = new Dictionary<PlayerCustomizationDummy, GameObject[]>();

		private static bool _loggedBoneHierarchy;

		private const float FallbackCharacterHeight = 1.7f;

		private const float ScaleMultiplier = 1.35f;

		[HarmonyPatch(typeof(CharacterCustomization), "SetCharacterOutfit")]
		[HarmonyPostfix]
		public static void OnSetOutfit(CharacterCustomization __instance, int index)
		{
			if (Plugin.ReplaceOutfits.Value && Plugin.LegoCharacterPartSets.Count != 0)
			{
				ApplyLegoModel(__instance);
			}
		}

		[HarmonyPatch(typeof(CharacterCustomization), "RandomizeCosmetics")]
		[HarmonyPostfix]
		public static void OnRandomize(CharacterCustomization __instance)
		{
			if (Plugin.ReplaceOutfits.Value && Plugin.LegoCharacterPartSets.Count != 0)
			{
				ApplyLegoModel(__instance);
			}
		}

		[HarmonyPatch(typeof(CharacterCustomization), "Start")]
		[HarmonyPostfix]
		public static void OnStart(CharacterCustomization __instance)
		{
			if (Plugin.ReplaceOutfits.Value && Plugin.LegoCharacterPartSets.Count != 0)
			{
				ApplyLegoModel(__instance);
			}
		}

		private static void ApplyLegoModel(CharacterCustomization customization)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)customization == (Object)null)
			{
				return;
			}
			CustomizationRefs refs = customization.refs;
			if ((Object)(object)refs == (Object)null || (Object)(object)refs.mainRenderer == (Object)null)
			{
				return;
			}
			SkinnedMeshRenderer mainRenderer = refs.mainRenderer;
			ObjMeshLoader.StealShaderFromRenderer((Renderer)(object)mainRenderer);
			Bounds bounds = ((Renderer)mainRenderer).bounds;
			float num = ((Bounds)(ref bounds)).size.y;
			if (num < 0.1f)
			{
				num = 1.7f;
			}
			float y = ((Bounds)(ref bounds)).min.y;
			Transform val = mainRenderer.rootBone ?? ((Component)mainRenderer).transform.parent ?? ((Component)customization).transform;
			float num2 = Mathf.Abs(val.lossyScale.y);
			if (num2 < 0.0001f)
			{
				num2 = 1f;
			}
			if (!_loggedBoneHierarchy)
			{
				_loggedBoneHierarchy = true;
				LogBoneHierarchy(mainRenderer, val);
			}
			HideAllCharacterRenderers(customization, refs);
			DestroyExistingParts(customization);
			LegoLoadout current = LegoLoadout.Current;
			string text = Plugin.LegoCharacterPartSets.Keys.FirstOrDefault();
			List<GameObject> list = new List<GameObject>();
			string text2 = text;
			if (text2 == null || !Plugin.LegoCharacterPartSets.TryGetValue(text2, out LegoCharacterParts value))
			{
				return;
			}
			float num3 = value.TotalHeight;
			if (num3 < 0.1f)
			{
				num3 = 63f;
			}
			float num4 = num * 1.35f / (num3 * num2);
			float num5 = float.MaxValue;
			string[] allPartTypes = LegoCharacterParts.AllPartTypes;
			foreach (string partType in allPartTypes)
			{
				GameObject part = value.GetPart(partType);
				if ((Object)(object)part == (Object)null)
				{
					continue;
				}
				MeshFilter component = part.GetComponent<MeshFilter>();
				if ((Object)(object)((component != null) ? component.sharedMesh : null) != (Object)null)
				{
					Bounds bounds2 = component.sharedMesh.bounds;
					if (((Bounds)(ref bounds2)).min.y < num5)
					{
						bounds2 = component.sharedMesh.bounds;
						num5 = ((Bounds)(ref bounds2)).min.y;
					}
				}
			}
			if (num5 == float.MaxValue)
			{
				num5 = 0f;
			}
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(val.position.x, y, val.position.z);
			Vector3 val3 = val.InverseTransformPoint(val2);
			float num6 = num5 * num4;
			Vector3 localPosition = default(Vector3);
			((Vector3)(ref localPosition))..ctor(0f, val3.y - num6, 0f);
			for (int j = 0; j < LegoCharacterParts.AllPartTypes.Length; j++)
			{
				string text3 = LegoCharacterParts.AllPartTypes[j];
				string boneName = LegoCharacterParts.BoneNames[j];
				string text4 = current.GetPartCharacter(text3) ?? text;
				if (text4 == null || !Plugin.LegoCharacterPartSets.TryGetValue(text4, out LegoCharacterParts value2))
				{
					continue;
				}
				GameObject part2 = value2.GetPart(text3);
				if ((Object)(object)part2 == (Object)null)
				{
					continue;
				}
				Transform targetBone = FindBone(mainRenderer, boneName) ?? val;
				GameObject val4 = Object.Instantiate<GameObject>(part2, val);
				((Object)val4).name = "Lego_" + text3 + "_" + text4;
				val4.SetActive(true);
				val4.layer = ((Component)val).gameObject.layer;
				val4.transform.localScale = Vector3.one * num4;
				val4.transform.localRotation = Quaternion.identity;
				val4.transform.localPosition = localPosition;
				ConvertToSingleBoneSkin(val4, targetBone, val);
				Renderer component2 = val4.GetComponent<Renderer>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.enabled = true;
					component2.shadowCastingMode = (ShadowCastingMode)1;
					Color legoColor = Plugin.GetLegoColor(text4);
					SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((component2 is SkinnedMeshRenderer) ? component2 : null);
					if (val5 != null)
					{
						ObjMeshLoader.ApplyGameShaderToSkinnedRenderer(val5, legoColor, text4);
					}
					else
					{
						MeshRenderer val6 = (MeshRenderer)(object)((component2 is MeshRenderer) ? component2 : null);
						if (val6 != null)
						{
							ObjMeshLoader.ApplyGameShaderToRenderer(val6, legoColor, text4);
						}
					}
				}
				list.Add(val4);
			}
			foreach (GameObject item in list)
			{
				LegoHeadCulling.SetPartLayer(item);
			}
			SpawnedLegoParts[customization] = list.ToArray();
			Plugin.Log.LogInfo((object)$"LEGO multi-part applied: {list.Count} parts on layer {31}, scale={num4:F4} charH={num:F2}");
		}

		private static void ConvertToSingleBoneSkin(GameObject part, Transform targetBone, Transform rootBone)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			MeshFilter component = part.GetComponent<MeshFilter>();
			MeshRenderer component2 = part.GetComponent<MeshRenderer>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null))
			{
				Mesh val = Object.Instantiate<Mesh>(component.sharedMesh);
				BoneWeight[] array = (BoneWeight[])(object)new BoneWeight[val.vertexCount];
				for (int i = 0; i < array.Length; i++)
				{
					int num = i;
					BoneWeight val2 = default(BoneWeight);
					((BoneWeight)(ref val2)).boneIndex0 = 0;
					((BoneWeight)(ref val2)).weight0 = 1f;
					array[num] = val2;
				}
				val.boneWeights = array;
				Matrix4x4[] bindposes = (Matrix4x4[])(object)new Matrix4x4[1] { targetBone.worldToLocalMatrix * part.transform.localToWorldMatrix };
				val.bindposes = bindposes;
				Material material = ((Renderer)component2).material;
				Object.DestroyImmediate((Object)(object)component2);
				Object.DestroyImmediate((Object)(object)component);
				SkinnedMeshRenderer val3 = part.AddComponent<SkinnedMeshRenderer>();
				val3.sharedMesh = val;
				((Renderer)val3).material = material;
				val3.bones = (Transform[])(object)new Transform[1] { targetBone };
				val3.rootBone = rootBone;
				((Renderer)val3).localBounds = val.bounds;
				val3.updateWhenOffscreen = true;
			}
		}

		private static void DestroyExistingParts(CharacterCustomization customization)
		{
			if (!SpawnedLegoParts.TryGetValue(customization, out GameObject[] value))
			{
				return;
			}
			GameObject[] array = value;
			foreach (GameObject val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static Transform? FindBone(SkinnedMeshRenderer smr, string boneName)
		{
			if (smr.bones == null)
			{
				return null;
			}
			Transform[] bones = smr.bones;
			foreach (Transform val in bones)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name == boneName)
				{
					return val;
				}
			}
			return null;
		}

		private static void LogBoneHierarchy(SkinnedMeshRenderer smr, Transform rootBone)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)"=== CHARACTER SKELETON DEBUG ===");
			ManualLogSource log = Plugin.Log;
			Bounds bounds = ((Renderer)smr).bounds;
			object arg = ((Bounds)(ref bounds)).center;
			bounds = ((Renderer)smr).bounds;
			object arg2 = ((Bounds)(ref bounds)).size;
			bounds = ((Renderer)smr).bounds;
			log.LogInfo((object)$"charBounds: center={arg} size={arg2} min={((Bounds)(ref bounds)).min}");
			Plugin.Log.LogInfo((object)string.Format("rootBone: {0} lossyScale={1}", ((Object)(object)smr.rootBone != (Object)null) ? ((Object)smr.rootBone).name : "NULL", rootBone.lossyScale));
			if (smr.bones != null)
			{
				Plugin.Log.LogInfo((object)$"Total bones: {smr.bones.Length}");
				for (int i = 0; i < smr.bones.Length; i++)
				{
					Transform val = smr.bones[i];
					if ((Object)(object)val != (Object)null)
					{
						ManualLogSource log2 = Plugin.Log;
						object arg3 = i;
						string name = ((Object)val).name;
						Transform parent = val.parent;
						log2.LogInfo((object)$"  bone[{arg3}]: {name} (parent={((parent != null) ? ((Object)parent).name : null)})");
					}
				}
			}
			Plugin.Log.LogInfo((object)"=== END SKELETON DEBUG ===");
		}

		[HarmonyPatch(typeof(PlayerCustomizationDummy), "SetPlayerCostume")]
		[HarmonyPostfix]
		public static void OnDummyCostume(PlayerCustomizationDummy __instance, int index)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ReplaceOutfits.Value || Plugin.LegoCharacterPartSets.Count == 0)
			{
				return;
			}
			CustomizationRefs refs = __instance.refs;
			if ((Object)(object)refs == (Object)null || (Object)(object)refs.mainRenderer == (Object)null)
			{
				return;
			}
			DestroyDummyParts(__instance);
			HideAllCharacterRenderers(null, refs);
			SkinnedMeshRenderer mainRenderer = refs.mainRenderer;
			ObjMeshLoader.StealShaderFromRenderer((Renderer)(object)mainRenderer);
			Bounds bounds = ((Renderer)mainRenderer).bounds;
			float num = ((Bounds)(ref bounds)).size.y;
			if (num < 0.1f)
			{
				num = 1.7f;
			}
			Transform val = mainRenderer.rootBone ?? ((Component)mainRenderer).transform.parent ?? ((Component)__instance).transform;
			float num2 = Mathf.Abs(val.lossyScale.y);
			if (num2 < 0.0001f)
			{
				num2 = 1f;
			}
			LegoLoadout current = LegoLoadout.Current;
			string text = Plugin.LegoCharacterPartSets.Keys.FirstOrDefault();
			if (text == null || !Plugin.LegoCharacterPartSets.TryGetValue(text, out LegoCharacterParts value))
			{
				return;
			}
			float num3 = value.TotalHeight;
			if (num3 < 0.1f)
			{
				num3 = 63f;
			}
			float num4 = num * 1.35f / (num3 * num2);
			List<GameObject> list = new List<GameObject>();
			for (int i = 0; i < LegoCharacterParts.AllPartTypes.Length; i++)
			{
				string text2 = LegoCharacterParts.AllPartTypes[i];
				string text3 = current.GetPartCharacter(text2) ?? text;
				if (text3 == null || !Plugin.LegoCharacterPartSets.TryGetValue(text3, out LegoCharacterParts value2))
				{
					continue;
				}
				GameObject part = value2.GetPart(text2);
				if ((Object)(object)part == (Object)null)
				{
					continue;
				}
				GameObject val2 = Object.Instantiate<GameObject>(part, val);
				((Object)val2).name = "LegoDummy_" + text2;
				val2.SetActive(true);
				val2.layer = ((Component)val).gameObject.layer;
				val2.transform.localScale = Vector3.one * num4;
				val2.transform.localRotation = Quaternion.identity;
				val2.transform.localPosition = Vector3.zero;
				Renderer component = val2.GetComponent<Renderer>();
				if ((Object)(object)component != (Object)null)
				{
					component.enabled = true;
					Color legoColor = Plugin.GetLegoColor(text3);
					MeshRenderer val3 = (MeshRenderer)(object)((component is MeshRenderer) ? component : null);
					if (val3 != null)
					{
						ObjMeshLoader.ApplyGameShaderToRenderer(val3, legoColor, text3);
					}
				}
				list.Add(val2);
			}
			SpawnedDummyParts[__instance] = list.ToArray();
		}

		[HarmonyPatch(typeof(PlayerCustomizationDummy), "UpdateDummy")]
		[HarmonyPostfix]
		public static void OnDummyUpdate(PlayerCustomizationDummy __instance)
		{
			if (Plugin.ReplaceOutfits.Value && Plugin.LegoCharacterPartSets.Count != 0 && !SpawnedDummyParts.ContainsKey(__instance))
			{
				OnDummyCostume(__instance, 0);
			}
		}

		private static void DestroyDummyParts(PlayerCustomizationDummy dummy)
		{
			if (!SpawnedDummyParts.TryGetValue(dummy, out GameObject[] value))
			{
				return;
			}
			GameObject[] array = value;
			foreach (GameObject val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
			SpawnedDummyParts.Remove(dummy);
		}

		public static void RefreshAll()
		{
			foreach (PlayerCustomizationDummy item in SpawnedDummyParts.Keys.ToList())
			{
				if (!((Object)(object)item == (Object)null))
				{
					DestroyDummyParts(item);
					OnDummyCostume(item, 0);
				}
			}
			foreach (CharacterCustomization item2 in SpawnedLegoParts.Keys.ToList())
			{
				if ((Object)(object)item2 != (Object)null)
				{
					ApplyLegoModel(item2);
				}
			}
		}

		private static void HideAllCharacterRenderers(CharacterCustomization? customization, CustomizationRefs refs)
		{
			if ((Object)(object)refs.mainRenderer != (Object)null)
			{
				((Renderer)refs.mainRenderer).enabled = false;
			}
			if ((Object)(object)refs.mainRendererShadow != (Object)null)
			{
				((Renderer)refs.mainRendererShadow).enabled = false;
			}
			if ((Object)(object)refs.shorts != (Object)null)
			{
				refs.shorts.enabled = false;
			}
			if ((Object)(object)refs.skirt != (Object)null)
			{
				refs.skirt.enabled = false;
			}
			if ((Object)(object)refs.skirtShadow != (Object)null)
			{
				refs.skirtShadow.enabled = false;
			}
			if ((Object)(object)refs.shortsShadow != (Object)null)
			{
				refs.shortsShadow.enabled = false;
			}
			if ((Object)(object)refs.mouthRenderer != (Object)null)
			{
				refs.mouthRenderer.enabled = false;
			}
			if ((Object)(object)refs.headShadow != (Object)null)
			{
				refs.headShadow.enabled = false;
			}
			if ((Object)(object)refs.sashRenderer != (Object)null)
			{
				refs.sashRenderer.enabled = false;
			}
			if (refs.EyeRenderers != null)
			{
				Renderer[] eyeRenderers = refs.EyeRenderers;
				foreach (Renderer val in eyeRenderers)
				{
					if ((Object)(object)val != (Object)null)
					{
						val.enabled = false;
					}
				}
			}
			if ((Object)(object)refs.accessoryRenderer != (Object)null)
			{
				refs.accessoryRenderer.enabled = false;
			}
			if (refs.playerHats != null)
			{
				Renderer[] playerHats = refs.playerHats;
				foreach (Renderer val2 in playerHats)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						val2.enabled = false;
					}
				}
			}
			if (!((Object)(object)customization != (Object)null))
			{
				return;
			}
			Renderer[] componentsInChildren = ((Component)customization).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren)
			{
				if (!((Object)((Component)val3).gameObject).name.StartsWith("Lego_") && !((Object)((Component)val3).gameObject).name.StartsWith("LegoDummy_"))
				{
					val3.enabled = false;
				}
			}
		}
	}
	[HarmonyPatch]
	public static class LegoPassportHijack
	{
		private sealed class Opt
		{
			public string? Char;

			public CustomizationOption Option;
		}

		private static readonly Dictionary<Type, string> TypeToCat = new Dictionary<Type, string>
		{
			{
				(Type)0,
				"heads"
			},
			{
				(Type)40,
				"torsos"
			},
			{
				(Type)20,
				"arms"
			},
			{
				(Type)30,
				"legs"
			},
			{
				(Type)50,
				"hats"
			},
			{
				(Type)10,
				"helmets"
			},
			{
				(Type)60,
				"hair"
			}
		};

		private static readonly Dictionary<string, List<Opt>> _registry = new Dictionary<string, List<Opt>>();

		private static readonly HashSet<CustomizationOption> _ourOptions = new HashSet<CustomizationOption>();

		private static bool _built;

		private static Texture2D? _noneTex;

		private static string PartTypeFor(string cat)
		{
			return cat switch
			{
				"heads" => "head", 
				"torsos" => "torso", 
				"arms" => "armR", 
				"legs" => "legR", 
				"hats" => "hat", 
				"helmets" => "helmet", 
				"hair" => "hair", 
				_ => "head", 
			};
		}

		private static bool IsAccessory(string cat)
		{
			switch (cat)
			{
			case "hats":
			case "helmets":
			case "hair":
				return true;
			default:
				return false;
			}
		}

		private static string? CatForType(Type t)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (!TypeToCat.TryGetValue(t, out string value))
			{
				return null;
			}
			return value;
		}

		private static void EnsureRegistry()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			if (_built)
			{
				return;
			}
			_built = true;
			LegoPassportUI.GenerateThumbnails();
			_noneTex = new Texture2D(8, 8, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[64];
			for (int i = 0; i < 64; i++)
			{
				array[i] = new Color(0.25f, 0.25f, 0.28f);
			}
			_noneTex.SetPixels(array);
			_noneTex.Apply();
			Object.DontDestroyOnLoad((Object)(object)_noneTex);
			foreach (KeyValuePair<Type, string> item in TypeToCat)
			{
				Type key = item.Key;
				string value = item.Value;
				string partType = PartTypeFor(value);
				List<Opt> list = new List<Opt>();
				if (IsAccessory(value))
				{
					list.Add(new Opt
					{
						Char = null,
						Option = MakeOption(_noneTex, key)
					});
				}
				foreach (string item2 in Plugin.LegoCharacterPartSets.Keys.OrderBy((string k) => k))
				{
					if (!((Object)(object)Plugin.LegoCharacterPartSets[item2].GetPart(partType) == (Object)null))
					{
						Texture2D thumb = LegoPassportUI.GetThumb(item2, partType);
						list.Add(new Opt
						{
							Char = item2,
							Option = MakeOption(thumb, key)
						});
					}
				}
				_registry[value] = list;
				Plugin.Log.LogInfo((object)$"Passport tab '{value}' ({key}): {list.Count} options");
			}
		}

		private static CustomizationOption MakeOption(Texture2D? thumb, Type type)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			CustomizationOption val = ScriptableObject.CreateInstance<CustomizationOption>();
			val.type = type;
			val.texture = (Texture)(object)thumb;
			val.isBlank = false;
			_ourOptions.Add(val);
			return val;
		}

		[HarmonyPatch(typeof(PassportManager), "Initialize")]
		[HarmonyPostfix]
		public static void OnInit()
		{
		}

		[HarmonyPatch(typeof(Customization), "GetList")]
		[HarmonyPostfix]
		public static void PostGetList(Type type, ref CustomizationOption[] __result)
		{
		}

		[HarmonyPatch(typeof(PassportButton), "SetButton")]
		[HarmonyPostfix]
		public static void PostSetButton(PassportButton __instance, CustomizationOption option)
		{
		}

		[HarmonyPatch(typeof(PassportManager), "SetOption")]
		[HarmonyPrefix]
		public static bool PreSetOption(PassportManager __instance, CustomizationOption option, int index)
		{
			return true;
		}
	}
	public static class LegoPassportUI
	{
		private static readonly Dictionary<string, Texture2D> _thumbs = new Dictionary<string, Texture2D>();

		private static bool _generated;

		public static Texture2D? GetThumb(string charName, string partType)
		{
			if (!_thumbs.TryGetValue(charName + ":" + partType, out Texture2D value))
			{
				return null;
			}
			return value;
		}

		public static void GenerateThumbnails()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			if (_generated)
			{
				return;
			}
			_generated = true;
			GameObject val = new GameObject("LegoThumbCam");
			Camera val2 = val.AddComponent<Camera>();
			val2.clearFlags = (CameraClearFlags)2;
			val2.backgroundColor = Color.clear;
			val2.orthographic = true;
			val2.cullingMask = 1073741824;
			((Behaviour)val2).enabled = false;
			RenderTexture val3 = (val2.targetTexture = new RenderTexture(128, 128, 16));
			val.transform.position = new Vector3(0f, 1000f, -50f);
			val.transform.LookAt(new Vector3(0f, 1000f, 0f));
			foreach (KeyValuePair<string, LegoCharacterParts> legoCharacterPartSet in Plugin.LegoCharacterPartSets)
			{
				string[] allPartTypes = LegoCharacterParts.AllPartTypes;
				foreach (string text in allPartTypes)
				{
					GameObject part = legoCharacterPartSet.Value.GetPart(text);
					if (!((Object)(object)part == (Object)null))
					{
						GameObject val5 = Object.Instantiate<GameObject>(part);
						val5.SetActive(true);
						SetLayerRecursive(val5, 30);
						MeshFilter componentInChildren = val5.GetComponentInChildren<MeshFilter>();
						if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.sharedMesh != (Object)null)
						{
							Bounds bounds = componentInChildren.sharedMesh.bounds;
							val5.transform.position = new Vector3(0f - ((Bounds)(ref bounds)).center.x, 1000f - ((Bounds)(ref bounds)).center.y, 0f - ((Bounds)(ref bounds)).center.z);
							val2.orthographicSize = Mathf.Max(((Bounds)(ref bounds)).extents.x, ((Bounds)(ref bounds)).extents.y) * 1.2f + 0.001f;
						}
						val2.Render();
						RenderTexture.active = val3;
						Texture2D val6 = new Texture2D(128, 128, (TextureFormat)4, false);
						val6.ReadPixels(new Rect(0f, 0f, 128f, 128f), 0, 0);
						val6.Apply();
						RenderTexture.active = null;
						Object.DontDestroyOnLoad((Object)(object)val6);
						_thumbs[legoCharacterPartSet.Key + ":" + text] = val6;
						Object.Destroy((Object)(object)val5);
					}
				}
			}
			Object.Destroy((Object)(object)val);
			val3.Release();
			Plugin.Log.LogInfo((object)$"Generated {_thumbs.Count} part thumbnails");
		}

		private static void SetLayerRecursive(GameObject go, int layer)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			go.layer = layer;
			foreach (Transform item in go.transform)
			{
				Transform val = item;
				SetLayerRecursive(((Component)val).gameObject, layer);
			}
		}
	}
	public class LegoReplacement : MonoBehaviour
	{
	}
	public class LegoSceneScanner : MonoBehaviour
	{
		private static readonly HashSet<int> ReplacedTrees = new HashSet<int>();

		private static readonly HashSet<int> ReplacedBridges = new HashSet<int>();

		private static readonly HashSet<int> ReplacedBushes = new HashSet<int>();

		private static readonly HashSet<int> ReplacedLuggage = new HashSet<int>();

		private static readonly HashSet<int> ReplacedFoliage = new HashSet<int>();

		private static readonly HashSet<int> ReplacedBingBong = new HashSet<int>();

		private static readonly HashSet<int> ReplacedRoot = new HashSet<int>();

		private static readonly HashSet<int> ReplacedChess = new HashSet<int>();

		private static readonly string[] ChessKeywords = new string[6] { "king", "queen", "bishop", "knight", "rook", "pawn" };

		private static readonly HashSet<int> HiddenCanopies = new HashSet<int>();

		private static readonly string[] FoliageKeywords = new string[5] { "fern", "grass", "leaf", "frond", "sprout" };

		private float _scanInterval = 5f;

		private float _timer;

		private static readonly string[] TrunkMeshKeywords = new string[3] { "trunk", "gianttree", "tree platform" };

		private static readonly string[] CanopyMeshKeywords = new string[6] { "crown", "foliage", "leaves", "treeflower", "pineleaves", "pine berry" };

		public static string ChessSkinFor(string mn)
		{
			if (mn.Contains("king"))
			{
				return "Vader";
			}
			if (mn.Contains("queen"))
			{
				return "Leia";
			}
			if (mn.Contains("bishop"))
			{
				if (!mn.Contains("_f"))
				{
					return "QuiGon";
				}
				return "ObiWan";
			}
			if (mn.Contains("knight"))
			{
				return "BobaFett";
			}
			if (mn.Contains("rook"))
			{
				if (!mn.Contains("_f"))
				{
					return "DarthMaul";
				}
				return "Chewbacca";
			}
			if (mn.Contains("pawn"))
			{
				if (!mn.Contains("_f"))
				{
					return "Batman";
				}
				return "Stormtrooper";
			}
			return null;
		}

		private void Update()
		{
			_timer += Time.deltaTime;
			if (!(_timer < _scanInterval))
			{
				_timer = 0f;
				if (Plugin.ReplaceBushes.Value && (Object)(object)Plugin.LegoBushPrefab != (Object)null)
				{
					ScanBushes();
				}
				if (Plugin.ReplaceLuggage.Value && (Object)(object)Plugin.LegoChestPrefab != (Object)null)
				{
					ScanLuggage();
				}
				if (Plugin.ReplaceTrees.Value && (Object)(object)Plugin.LegoTreePrefab != (Object)null)
				{
					ScanTrees();
					ScanDecorativeTrees();
				}
				if (Plugin.ReplaceFoliage.Value && (Object)(object)Plugin.LegoLeafPrefab != (Object)null)
				{
					ScanFoliage();
				}
				if (Plugin.ReplaceBridges.Value && (Object)(object)Plugin.LegoBridgePrefab != (Object)null)
				{
					ScanBridges();
				}
				if (Plugin.ReplaceBingBong.Value && (Object)(object)Plugin.LegoMinikitPrefab != (Object)null)
				{
					ScanBingBong();
				}
				if (Plugin.ReplaceMedicinalRoot.Value && (Object)(object)Plugin.LegoCarrotPrefab != (Object)null)
				{
					ScanMedicinalRoot();
				}
				if (Plugin.ReplaceChess.Value && Plugin.LegoMinifigPrefabs.Count > 0)
				{
					ScanChess();
				}
			}
		}

		private void ScanChess()
		{
			MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent<LegoReplacement>() != (Object)null)
				{
					continue;
				}
				string text = ((Object)val.sharedMesh).name.ToLowerInvariant();
				if (!ContainsAny(text, ChessKeywords))
				{
					continue;
				}
				int instanceID = ((Object)val).GetInstanceID();
				if (!ReplacedChess.Add(instanceID))
				{
					continue;
				}
				string text2 = ChessSkinFor(text);
				if (text2 == null)
				{
					continue;
				}
				GameObject val2 = null;
				foreach (GameObject legoMinifigPrefab in Plugin.LegoMinifigPrefabs)
				{
					if (((Object)legoMinifigPrefab).name == "Minifig_" + text2)
					{
						val2 = legoMinifigPrefab;
						break;
					}
				}
				if (!((Object)(object)val2 == (Object)null))
				{
					ReplaceUpright(((Component)val).gameObject, val2, flipX: false);
					Plugin.Log.LogInfo((object)("Replaced chess piece: mesh='" + ((Object)val.sharedMesh).name + "' -> " + ((Object)val2).name));
				}
			}
		}

		private void ScanMedicinalRoot()
		{
			MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent<LegoReplacement>() != (Object)null)
				{
					continue;
				}
				bool flag = ((Object)((Component)val).gameObject).name.ToLowerInvariant().Contains("medicinal");
				if (!flag)
				{
					Material[] sharedMaterials = ((Renderer)component).sharedMaterials;
					if (sharedMaterials != null)
					{
						Material[] array2 = sharedMaterials;
						foreach (Material val2 in array2)
						{
							if ((Object)(object)val2 != (Object)null && ((Object)val2).name.ToLowerInvariant().Contains("medicinal"))
							{
								flag = true;
								break;
							}
						}
					}
				}
				if (flag)
				{
					int instanceID = ((Object)val).GetInstanceID();
					if (ReplacedRoot.Add(instanceID))
					{
						ReplaceUpright(((Component)val).gameObject, Plugin.LegoCarrotPrefab, flipX: false, Plugin.CarrotScale.Value);
						Plugin.Log.LogInfo((object)("Replaced medicinal root: " + ((Object)((Component)val).gameObject).name + " mesh='" + ((Object)val.sharedMesh).name + "'"));
					}
				}
			}
		}

		private void ScanBingBong()
		{
			MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled && !((Object)(object)((Component)val).GetComponentInParent<LegoReplacement>() != (Object)null) && ((Object)val.sharedMesh).name.ToLowerInvariant().Contains("bingbong"))
				{
					int instanceID = ((Object)val).GetInstanceID();
					if (ReplacedBingBong.Add(instanceID))
					{
						ReplaceUpright(((Component)val).gameObject, Plugin.LegoMinikitPrefab, flipX: false, Plugin.MinikitScale.Value);
						Plugin.Log.LogInfo((object)("Replaced Bing Bong: " + ((Object)((Component)val).gameObject).name + " mesh='" + ((Object)val.sharedMesh).name + "'"));
					}
				}
			}
		}

		private void ScanFoliage()
		{
			MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent<LegoReplacement>() != (Object)null || HasBushMaterial(component))
				{
					continue;
				}
				string s = ((Object)val.sharedMesh).name.ToLowerInvariant();
				if (ContainsAny(s, FoliageKeywords))
				{
					LODGroup componentInParent = ((Component)val).GetComponentInParent<LODGroup>();
					GameObject val2 = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).gameObject : ((Component)val).gameObject);
					if (ReplacedFoliage.Add(((Object)val2).GetInstanceID()))
					{
						ReplaceUpright(val2, Plugin.LegoLeafPrefab, flipX: false, Plugin.LeafScale.Value);
						Plugin.Log.LogInfo((object)("Replaced foliage: " + ((Object)((Component)val).gameObject).name + " mesh='" + ((Object)val.sharedMesh).name + "'"));
					}
				}
			}
		}

		private static bool HasBushMaterial(MeshRenderer rend)
		{
			Material[] sharedMaterials = ((Renderer)rend).sharedMaterials;
			if (sharedMaterials != null)
			{
				Material[] array = sharedMaterials;
				foreach (Material val in array)
				{
					if ((Object)(object)val != (Object)null && ((Object)val).name.ToLowerInvariant().Contains("bush"))
					{
						return true;
					}
				}
			}
			return false;
		}

		private void ScanBushes()
		{
			MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent<LegoReplacement>() != (Object)null)
				{
					continue;
				}
				string text = ((Object)val.sharedMesh).name.ToLowerInvariant();
				if (HasBushMaterial(component) || text.Contains("bush") || text.Contains("shrub"))
				{
					LODGroup componentInParent = ((Component)val).GetComponentInParent<LODGroup>();
					GameObject val2 = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).gameObject : ((Component)val).gameObject);
					if (ReplacedBushes.Add(((Object)val2).GetInstanceID()))
					{
						ReplaceUpright(val2, Plugin.LegoBushPrefab, flipX: false, Plugin.BushScale.Value);
						Plugin.Log.LogInfo((object)("Replaced bush: " + ((Object)((Component)val).gameObject).name + " mesh='" + ((Object)val.sharedMesh).name + "'"));
					}
				}
			}
		}

		private void ScanLuggage()
		{
			MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled && !((Object)(object)((Component)val).GetComponentInParent<LegoReplacement>() != (Object)null) && ((Object)val.sharedMesh).name.ToLowerInvariant().Contains("luggage"))
				{
					int instanceID = ((Object)val).GetInstanceID();
					if (ReplacedLuggage.Add(instanceID))
					{
						ReplaceUpright(((Component)val).gameObject, Plugin.LegoChestPrefab, flipX: false, Plugin.ChestScale.Value);
						Plugin.Log.LogInfo((object)("Replaced luggage: " + ((Object)((Component)val).gameObject).name + " mesh='" + ((Object)val.sharedMesh).name + "'"));
					}
				}
			}
		}

		private void ScanTrees()
		{
			TreePlatform[] array = Object.FindObjectsOfType<TreePlatform>();
			foreach (TreePlatform val in array)
			{
				int instanceID = ((Object)val).GetInstanceID();
				if (ReplacedTrees.Add(instanceID))
				{
					ReplaceWithTree(((Component)val).gameObject);
					Plugin.Log.LogInfo((object)("Replaced tree (platform): " + ((Object)((Component)val).gameObject).name));
				}
			}
		}

		private void ScanDecorativeTrees()
		{
			MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
			foreach (MeshFilter val in array)
			{
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent<LegoReplacement>() != (Object)null || HasBushMaterial(component))
				{
					continue;
				}
				string text = ((Object)val.sharedMesh).name.ToLowerInvariant();
				bool flag = false;
				Material[] sharedMaterials = ((Renderer)component).sharedMaterials;
				if (sharedMaterials != null)
				{
					Material[] array2 = sharedMaterials;
					foreach (Material val2 in array2)
					{
						if ((Object)(object)val2 != (Object)null && ((Object)val2).name.ToLowerInvariant().Contains("palm"))
						{
							flag = true;
							break;
						}
					}
				}
				bool flag2 = ContainsAny(text, CanopyMeshKeywords);
				bool flag3 = flag || text == "tree" || ContainsAny(text, TrunkMeshKeywords);
				if (flag2 && !flag)
				{
					if (HiddenCanopies.Add(((Object)val).GetInstanceID()))
					{
						((Renderer)component).enabled = false;
					}
				}
				else if (flag3)
				{
					int instanceID = ((Object)val).GetInstanceID();
					if (ReplacedTrees.Add(instanceID))
					{
						ReplaceWithTree(((Component)val).gameObject);
						Plugin.Log.LogInfo((object)$"Replaced tree (decorative): {((Object)((Component)val).gameObject).name} mesh='{((Object)val.sharedMesh).name}' palm={flag}");
					}
				}
			}
		}

		private void ScanBridges()
		{
			BreakableBridge[] array = Object.FindObjectsOfType<BreakableBridge>();
			foreach (BreakableBridge val in array)
			{
				int instanceID = ((Object)val).GetInstanceID();
				if (ReplacedBridges.Add(instanceID))
				{
					ReplaceKeepOrientation(((Component)val).gameObject, Plugin.LegoBridgePrefab, 1f);
					Plugin.Log.LogInfo((object)("Replaced bridge: " + ((Object)((Component)val).gameObject).name));
				}
			}
		}

		private static bool ContainsAny(string s, string[] keys)
		{
			foreach (string value in keys)
			{
				if (s.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static void ReplaceWithTree(GameObject target)
		{
			ReplaceUpright(target, Plugin.LegoTreePrefab, flipX: true);
		}

		private static void ReplaceUpright(GameObject target, GameObject prefab, bool flipX, float scaleMult = 1f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: 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)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			Bounds val = default(Bounds);
			bool flag = false;
			Renderer[] componentsInChildren = target.GetComponentsInChildren<Renderer>();
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!flag)
				{
					val = val2.bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref val)).Encapsulate(val2.bounds);
				}
				val2.enabled = false;
			}
			GameObject val3 = Object.Instantiate<GameObject>(prefab);
			val3.SetActive(true);
			val3.AddComponent<LegoReplacement>();
			MeshFilter componentInChildren = val3.GetComponentInChildren<MeshFilter>();
			float num;
			Bounds bounds;
			if (!((Object)(object)componentInChildren != (Object)null) || !((Object)(object)componentInChildren.sharedMesh != (Object)null))
			{
				num = 1f;
			}
			else
			{
				bounds = componentInChildren.sharedMesh.bounds;
				num = ((Bounds)(ref bounds)).size.y;
			}
			float num2 = num;
			float num3 = (flag ? Mathf.Max(((Bounds)(ref val)).size.y, 0.1f) : 5f);
			float num4 = ((num2 > 0.001f) ? (num3 / num2) : 0.02f) * scaleMult;
			val3.transform.localScale = Vector3.one * num4;
			val3.transform.rotation = (flipX ? Quaternion.Euler(180f, 0f, 0f) : Quaternion.identity);
			if (flag)
			{
				val3.transform.position = new Vector3(((Bounds)(ref val)).center.x, ((Bounds)(ref val)).min.y, ((Bounds)(ref val)).center.z);
				Renderer componentInChildren2 = val3.GetComponentInChildren<Renderer>();
				if ((Object)(object)componentInChildren2 != (Object)null)
				{
					Transform transform = val3.transform;
					Vector3 position = transform.position;
					float y = ((Bounds)(ref val)).min.y;
					bounds = componentInChildren2.bounds;
					transform.position = position + new Vector3(0f, y - ((Bounds)(ref bounds)).min.y, 0f);
				}
			}
			val3.transform.SetParent(target.transform, true);
		}

		private static void ReplaceKeepOrientation(GameObject target, GameObject legoPrefab, float targetScale)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer[] componentsInChildren = target.GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val in componentsInChildren)
			{
				((Renderer)val).enabled = false;
			}
			SkinnedMeshRenderer[] componentsInChildren2 = target.GetComponentsInChildren<SkinnedMeshRenderer>();
			foreach (SkinnedMeshRenderer val2 in componentsInChildren2)
			{
				((Renderer)val2).enabled = false;
			}
			GameObject val3 = Object.Instantiate<GameObject>(legoPrefab, target.transform);
			val3.SetActive(true);
			val3.AddComponent<LegoReplacement>();
			val3.transform.localPosition = Vector3.zero;
			val3.transform.localRotation = Quaternion.identity;
			MeshFilter component = val3.GetComponent<MeshFilter>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null)
			{
				Bounds bounds = component.sharedMesh.bounds;
				float y = ((Bounds)(ref bounds)).size.y;
				if (y > 0.001f)
				{
					val3.transform.localScale = Vector3.one * (targetScale / y);
				}
			}
			else
			{
				val3.transform.localScale = Vector3.one * 0.01f;
			}
		}
	}
	public static class ObjMeshLoader
	{
		internal static Shader? CachedGameShader;

		internal static readonly Dictionary<string, Texture2D> LoadedTextures = new Dictionary<string, Texture2D>();

		internal static void StealShaderFromRenderer(Renderer renderer)
		{
			if (!((Object)(object)CachedGameShader != (Object)null) && !((Object)(object)renderer == (Object)null))
			{
				Material sharedMaterial = renderer.sharedMaterial;
				if ((Object)(object)sharedMaterial != (Object)null && (Object)(object)sharedMaterial.shader != (Object)null)
				{
					CachedGameShader = sharedMaterial.shader;
					Plugin.Log.LogInfo((object)("Captured game shader: " + ((Object)CachedGameShader).name));
				}
			}
		}

		internal static void ApplyGameShaderToSkinnedRenderer(SkinnedMeshRenderer target, Color color, string? textureName = null)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			Material material = ((Renderer)target).material;
			if ((Object)(object)material == (Object)null)
			{
				return;
			}
			if ((Object)(object)CachedGameShader != (Object)null)
			{
				material.shader = CachedGameShader;
			}
			if (textureName != null && LoadedTextures.TryGetValue(textureName, out Texture2D value))
			{
				if (material.HasProperty("_BaseMap"))
				{
					material.SetTexture("_BaseMap", (Texture)(object)value);
				}
				else if (material.HasProperty("_MainTex"))
				{
					material.SetTexture("_MainTex", (Texture)(object)value);
				}
				material.SetColor("_BaseColor", Color.white);
				Plugin.Log.LogInfo((object)("Applied texture '" + textureName + "' to skinned " + ((Object)target).name));
			}
			else if (material.HasProperty("_BaseColor"))
			{
				material.SetColor("_BaseColor", color);
			}
			else if (material.HasProperty("_Color"))
			{
				material.SetColor("_Color", color);
			}
			else
			{
				material.color = color;
			}
		}

		internal static void ApplyGameShaderToRenderer(MeshRenderer target, Color color, string? textureName = null)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			Material material = ((Renderer)target).material;
			if ((Object)(object)material == (Object)null)
			{
				return;
			}
			if ((Object)(object)CachedGameShader != (Object)null)
			{
				material.shader = CachedGameShader;
			}
			if (textureName != null && LoadedTextures.TryGetValue(textureName, out Texture2D value))
			{
				if (material.HasProperty("_BaseMap"))
				{
					material.SetTexture("_BaseMap", (Texture)(object)value);
				}
				else if (material.HasProperty("_MainTex"))
				{
					material.SetTexture("_MainTex", (Texture)(object)value);
				}
				material.SetColor("_BaseColor", Color.white);
				Plugin.Log.LogInfo((object)("Applied texture '" + textureName + "' to " + ((Object)target).name));
			}
			else if (material.HasProperty("_BaseColor"))
			{
				material.SetColor("_BaseColor", color);
			}
			else if (material.HasProperty("_Color"))
			{
				material.SetColor("_Color", color);
			}
			else
			{
				material.color = color;
			}
		}

		internal static void LoadTexturesFromFolder(string folder)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			string[] files = Directory.GetFiles(folder, "*.png");
			foreach (string path in files)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
				byte[] array = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
				if (ImageConversion.LoadImage(val, array))
				{
					((Object)val).name = fileNameWithoutExtension;
					LoadedTextures[fileNameWithoutExtension] = val;
					Object.DontDestroyOnLoad((Object)(object)val);
					Plugin.Log.LogInfo((object)$"Loaded texture: {fileNameWithoutExtension} ({((Texture)val).width}x{((Texture)val).height})");
				}
			}
		}

		public static Mesh? LoadObjMesh(string path)
		{
			List<string> materialNames;
			string mtllib;
			return LoadObjMesh(path, out materialNames, out mtllib);
		}

		public static Mesh? LoadObjMesh(string path, out List<string> materialNames, out string? mtllib)
		{
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Expected O, but got Unknown
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: 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)
			materialNames = new List<string>();
			mtllib = null;
			if (!File.Exists(path))
			{
				return null;
			}
			List<string> matNames = new List<string>();
			List<Vector3> rawV = new List<Vector3>();
			List<Vector3> rawVN = new List<Vector3>();
			List<Vector2> rawVT = new List<Vector2>();
			List<Vector3> vertices = new List<Vector3>();
			List<Vector3> normals = new List<Vector3>();
			List<Vector2> uvs = new List<Vector2>();
			Dictionary<(int, int, int), int> combo = new Dictionary<(int, int, int), int>();
			List<List<int>> subTris = new List<List<int>>();
			Dictionary<string, int> subByName = new Dictionary<string, int>();
			List<int> cur = null;
			foreach (string item in File.ReadLines(path))
			{
				if (string.IsNullOrWhiteSpace(item) || item[0] == '#')
				{
					continue;
				}
				string[] array = item.Split(' ', StringSplitOptions.RemoveEmptyEntries);
				if (array.Length < 2)
				{
					continue;
				}
				switch (array[0])
				{
				case "mtllib":
					mtllib = item.Substring(item.IndexOf(' ') + 1).Trim();
					break;
				case "usemtl":
					if (array.Length >= 2)
					{
						EnsureSub(array[1]);
					}
					break;
				case "v":
					if (array.Length >= 4)
					{
						rawV.Add(new Vector3(float.Parse(array[1], CultureInfo.InvariantCulture), float.Parse(array[2], CultureInfo.InvariantCulture), float.Parse(array[3], CultureInfo.InvariantCulture)));
					}
					break;
				case "vn":
					if (array.Length >= 4)
					{
						rawVN.Add(new Vector3(float.Parse(array[1], CultureInfo.InvariantCulture), float.Parse(array[2], CultureInfo.InvariantCulture), float.Parse(array[3], CultureInfo.InvariantCulture)));
					}
					break;
				case "vt":
					if (array.Length >= 3)
					{
						rawVT.Add(new Vector2(float.Parse(array[1], CultureInfo.InvariantCulture), float.Parse(array[2], CultureInfo.InvariantCulture)));
					}
					break;
				case "f":
				{
					if (cur == null)
					{
						EnsureSub("default");
					}
					List<int> list = new List<int>();
					for (int i = 1; i < array.Length; i++)
					{
						string[] array2 = array[i].Split('/');
						int vi = int.Parse(array2[0], CultureInfo.InvariantCulture) - 1;
						int ti = ((array2.Length > 1 && array2[1].Length > 0) ? (int.Parse(array2[1], CultureInfo.InvariantCulture) - 1) : (-1));
						int ni = ((array2.Length > 2 && array2[2].Length > 0) ? (int.Parse(array2[2], CultureInfo.InvariantCulture) - 1) : (-1));
						list.Add(GetVert(vi, ti, ni));
					}
					for (int j = 1; j < list.Count - 1; j++)
					{
						cur.Add(list[0]);
						cur.Add(list[j]);
						cur.Add(list[j + 1]);
					}
					break;
				}
				}
			}
			if (vertices.Count == 0)
			{
				return null;
			}
			Mesh val = new Mesh();
			((Object)val).name = Path.GetFileNameWithoutExtension(path);
			if (vertices.Count > 65535)
			{
				val.indexFormat = (IndexFormat)1;
			}
			materialNames = matNames;
			val.SetVertices(vertices);
			val.subMeshCount = subTris.Count;
			for (int k = 0; k < subTris.Count; k++)
			{
				val.SetTriangles(subTris[k], k);
			}
			if (normals.Count == vertices.Count)
			{
				val.SetNormals(normals);
			}
			else
			{
				val.RecalculateNormals();
			}
			if (uvs.Count == vertices.Count)
			{
				val.SetUVs(0, uvs);
			}
			val.RecalculateBounds();
			return val;
			void EnsureSub(string n)
			{
				if (!subByName.TryGetValue(n, out var value))
				{
					value = subTris.Count;
					subByName[n] = value;
					subTris.Add(new List<int>());
					matNames.Add(n);
				}
				cur = subTris[value];
			}
			int GetVert(int num, int num2, int num3)
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: 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_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				(int, int, int) key = (num, num2, num3);
				if (!combo.TryGetValue(key, out var value))
				{
					value = vertices.Count;
					vertices.Add((num >= 0 && num < rawV.Count) ? rawV[num] : Vector3.zero);
					uvs.Add((num2 >= 0 && num2 < rawVT.Count) ? rawVT[num2] : Vector2.zero);
					normals.Add((num3 >= 0 && num3 < rawVN.Count) ? rawVN[num3] : Vector3.zero);
					combo[key] = value;
				}
				return value;
			}
		}

		public static Dictionary<string, Color> ParseMtlColors(string mtlPath)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Color> dictionary = new Dictionary<string, Color>();
			if (!File.Exists(mtlPath))
			{
				return dictionary;
			}
			string text = null;
			foreach (string item in File.ReadLines(mtlPath))
			{
				string text2 = item.Trim();
				if (text2.StartsWith("newmtl "))
				{
					text = text2.Substring(7).Trim();
				}
				else if (text2.StartsWith("Kd ") && text != null)
				{
					string[] array = text2.Split(' ', StringSplitOptions.RemoveEmptyEntries);
					if (array.Length >= 4)
					{
						dictionary[text] = new Color(float.Parse(array[1], CultureInfo.InvariantCulture), float.Parse(array[2], CultureInfo.InvariantCulture), float.Parse(array[3], CultureInfo.InvariantCulture));
					}
				}
			}
			return dictionary;
		}

		public static Dictionary<string, string> ParseMtlTextures(string mtlPath)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!File.Exists(mtlPath))
			{
				return dictionary;
			}
			string text = null;
			foreach (string item in File.ReadLines(mtlPath))
			{
				string text2 = item.Trim();
				if (text2.StartsWith("newmtl "))
				{
					text = text2.Substring(7).Trim();
				}
				else if (text2.StartsWith("map_Kd ") && text != null)
				{
					dictionary[text] = Path.GetFileName(text2.Substring(7).Trim());
				}
			}
			return dictionary;
		}

		public static Texture2D? LoadTextureFile(string path)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			string key = path.ToLowerInvariant();
			if (LoadedTextures.TryGetValue(key, out Texture2D value))
			{
				return value;
			}
			if (!File.Exists(path))
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
			if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
			{
				return null;
			}
			((Object)val).name = Path.GetFileNameWithoutExtension(path);
			Object.DontDestroyOnLoad((Object)(object)val);
			LoadedTextures[key] = val;
			return val;
		}

		public static GameObject CreateGameObjectFromObj(string path, string name, Color color)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: 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_0235: 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_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_027e: Unknown result type (might be due to invalid IL or missing references)
			List<string> materialNames;
			string mtllib;
			Mesh val = LoadObjMesh(path, out materialNames, out mtllib);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Failed to load OBJ: " + path));
				GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)1);
				((Object)val2).name = name;
				Object.DontDestroyOnLoad((Object)(object)val2);
				val2.SetActive(false);
				return val2;
			}
			GameObject val3 = new GameObject(name);
			MeshFilter val4 = val3.AddComponent<MeshFilter>();
			val4.mesh = val;
			MeshRenderer val5 = val3.AddComponent<MeshRenderer>();
			string directoryName = Path.GetDirectoryName(path);
			string mtlPath = Path.Combine(directoryName, mtllib ?? (Path.GetFileNameWithoutExtension(path) + ".mtl"));
			Dictionary<string, Color> dictionary = ParseMtlColors(mtlPath);
			Dictionary<string, string> dictionary2 = ParseMtlTextures(mtlPath);
			Shader val6 = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
			int num = Mathf.Max(1, val.subMeshCount);
			Material[] array = (Material[])(object)new Material[num];
			for (int i = 0; i < num; i++)
			{
				Material val7 = new Material(val6);
				string text = ((i < materialNames.Count) ? materialNames[i] : null);
				string value;
				Texture2D val8 = ((text != null && dictionary2.TryGetValue(text, out value)) ? LoadTextureFile(Path.Combine(directoryName, value)) : null);
				if ((Object)(object)val8 != (Object)null)
				{
					if (val7.HasProperty("_BaseMap"))
					{
						val7.SetTexture("_BaseMap", (Texture)(object)val8);
					}
					val7.mainTexture = (Texture)(object)val8;
					if (val7.HasProperty("_BaseColor"))
					{
						val7.SetColor("_BaseColor", Color.white);
					}
					val7.color = Color.white;
					string text2 = ((Object)val8).name.ToLowerInvariant();
					if (text != null && (text2.Contains("face") || text2.Contains("bush")))
					{
						val7.EnableKeyword("_ALPHATEST_ON");
						if (val7.HasProperty("_AlphaClip"))
						{
							val7.SetFloat("_AlphaClip", 1f);
						}
						if (val7.HasProperty("_Cutoff"))
						{
							val7.SetFloat("_Cutoff", 0.4f);
						}
						val7.renderQueue = 2450;
						if (text2.Contains("bush") && val7.HasProperty("_Cull"))
						{
							val7.SetFloat("_Cull", 0f);
						}
					}
				}
				else
				{
					Color val9 = color;
					if (text != null && dictionary.TryGetValue(text, out var value2))
					{
						val9 = value2;
					}
					if (val7.HasProperty("_BaseColor"))
					{
						val7.SetColor("_BaseColor", val9);
					}
					if (val7.HasProperty("_Color"))
					{
						val7.SetColor("_Color", val9);
					}
					val7.color = val9;
				}
				if (val7.HasProperty("_Smoothness"))
				{
					val7.SetFloat("_Smoothness", 0.85f);
				}
				if (val7.HasProperty("_Metallic"))
				{
					val7.SetFloat("_Metallic", 0f);
				}
				array[i] = val7;
			}
			((Renderer)val5).sharedMaterials = array;
			ManualLogSource log = Plugin.Log;
			object[] obj = new object[5] { name, val.vertexCount, num, dictionary.Count, null };
			Bounds bounds = val.bounds;
			obj[4] = ((Bounds)(ref bounds)).size.y;
			log.LogInfo((object)string.Format("OBJ '{0}': verts={1}, submeshes={2}, mtlColors={3}, boundsY={4:F1}", obj));
			Object.DontDestroyOnLoad((Object)(object)val3);
			val3.SetActive(false);
			return val3;
		}
	}
	[BepInPlugin("Furter.LegoWorld", "LegoWorld", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		internal static readonly Dictionary<string, AssetBundle> LoadedBundles = new Dictionary<string, AssetBundle>();

		internal static readonly Dictionary<string, GameObject> LegoCharacterPrefabs = new Dictionary<string, GameObject>();

		internal static readonly Dictionary<string, LegoCharacterParts> LegoCharacterPartSets = new Dictionary<string, LegoCharacterParts>();

		internal static GameObject? LegoTreePrefab;

		internal static GameObject? LegoBridgePrefab;

		internal static GameObject? LegoBushPrefab;

		internal static GameObject? LegoChestPrefab;

		internal static GameObject? LegoLeafPrefab;

		internal static GameObject? LegoMinikitPrefab;

		internal static GameObject? LegoCarrotPrefab;

		internal static readonly List<GameObject> LegoMinifigPrefabs = new List<GameObject>();

		internal const bool PassportEnabled = false;

		internal static ConfigEntry<bool> ReplaceOutfits = null;

		internal static ConfigEntry<bool> ReplaceTrees = null;

		internal static ConfigEntry<bool> ReplaceBridges = null;

		internal static ConfigEntry<bool> ReplaceBushes = null;

		internal static ConfigEntry<float> BushScale = null;

		internal static ConfigEntry<bool> ReplaceLuggage = null;

		internal static ConfigEntry<float> ChestScale = null;

		internal static ConfigEntry<bool> ReplaceFoliage = null;

		internal static ConfigEntry<float> LeafScale = null;

		internal static ConfigEntry<bool> ReplaceBingBong = null;

		internal static ConfigEntry<float> MinikitScale = null;

		internal static ConfigEntry<bool> ReplaceMedicinalRoot = null;

		internal static ConfigEntry<float> CarrotScale = null;

		internal static ConfigEntry<bool> ReplaceChess = null;

		private static readonly Dictionary<string, Color> CharacterColors = new Dictionary<string, Color>
		{
			{
				"Batman",
				new Color(0.15f, 0.15f, 0.15f)
			},
			{
				"DaftPunk",
				new Color(0.7f, 0.5f, 0.1f)
			},
			{
				"DarthVader",
				new Color(0.1f, 0.1f, 0.12f)
			},
			{
				"HarleyQuinn",
				new Color(0.9f, 0.2f, 0.3f)
			},
			{
				"Peely",
				new Color(1f, 0.85f, 0.1f)
			},
			{
				"R2D2",
				new Color(0.8f, 0.85f, 0.9f)
			},
			{
				"SherifffDeadpool",
				new Color(0.8f, 0.1f, 0.15f)
			},
			{
				"Skeleton",
				new Color(0.9f, 0.9f, 0.85f)
			},
			{
				"SpiderMan",
				new Color(0.8f, 0.1f, 0.1f)
			},
			{
				"Superman",
				new Color(0.1f, 0.2f, 0.8f)
			},
			{
				"Yoda",
				new Color(0.3f, 0.6f, 0.2f)
			},
			{
				"LegoTree",
				new Color(0.2f, 0.6f, 0.15f)
			},
			{
				"LegoBridge",
				new Color(0.5f, 0.35f, 0.2f)
			}
		};

		public const string Id = "Furter.LegoWorld";

		internal static ManualLogSource Log { get; private set; } = null;

		internal static Plugin Instance { get; private set; } = null;

		public static string Name => "LegoWorld";

		public static string Version => "0.1.0";

		private void Awake()
		{
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Expected O, but got Unknown
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			ReplaceOutfits = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceOutfits", true, "Replace character outfits with LEGO models");
			ReplaceTrees = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceTrees", true, "Replace trees with LEGO tree model");
			ReplaceBridges = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceBridges", true, "Replace bridges with LEGO bridge model");
			ReplaceBushes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceBushes", true, "Replace bushes with the bush model");
			BushScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BushScale", 1.6f, "Bush size multiplier (1 = match original bush size)");
			ReplaceLuggage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceLuggage", true, "Replace luggage with the LEGO treasure chest");
			ChestScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChestScale", 1f, "Chest size multiplier (1 = match original luggage size)");
			ReplaceFoliage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceFoliage", true, "Replace leftover leaf/grass meshes (ferns, sprouts, grass) with the LEGO leaf");
			LeafScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "LeafScale", 1f, "Leaf size multiplier (1 = match original foliage size)");
			ReplaceBingBong = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceBingBong", true, "Replace the Bing Bong item with the LEGO minikit canister");
			MinikitScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MinikitScale", 1f, "Minikit canister size multiplier (1 = match Bing Bong size)");
			ReplaceChess = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceChess", true, "Replace chess pieces with the LEGO minifig skins (small)");
			ReplaceMedicinalRoot = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceMedicinalRoot", true, "Replace the medicinal root item with the LEGO carrot");
			CarrotScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CarrotScale", 1f, "Carrot size multiplier (1 = match the medicinal root size)");
			LegoMinikitPrefab = LegoMinikitFactory.Build();
			LegoLoadout.BindConfig(((BaseUnityPlugin)this).Config);
			LoadAssetBundles();
			_harmony = new Harmony("Furter.LegoWorld");
			_harmony.PatchAll();
			GameObject val = new GameObject("LegoWorldScanner");
			Object.DontDestroyOnLoad((Object)(object)val);
			val.AddComponent<LegoSceneScanner>();
			Log.LogInfo((object)$"LegoWorld loaded! {LegoCharacterPartSets.Count} multi-part + {LegoCharacterPrefabs.Count} single-mesh characters, Tree={(Object)(object)LegoTreePrefab != (Object)null}, Bridge={(Object)(object)LegoBridgePrefab != (Object)null}");
		}

		private void LoadAssetBundles()
		{
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			string path = Path.Combine(directoryName, "legobundles");
			if (Directory.Exists(path))
			{
				string[] files = Directory.GetFiles(path, "*.legoworld");
				foreach (string text in files)
				{
					try
					{
						AssetBundle val = AssetBundle.LoadFromFile(text);
						if ((Object)(object)val == (Object)null)
						{
							continue;
						}
						string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
						LoadedBundles[fileNameWithoutExtension] = val;
						GameObject[] array = val.LoadAllAssets<GameObject>();
						GameObject[] array2 = array;
						foreach (GameObject val2 in array2)
						{
							if (((Object)val2).name == "LegoTree")
							{
								LegoTreePrefab = val2;
							}
							else if (((Object)val2).name == "LegoBridge")
							{
								LegoBridgePrefab = val2;
							}
							else if (((Object)val2).name == "LegoBush")
							{
								LegoBushPrefab = val2;
							}
							else if (((Object)val2).name == "LegoChest")
							{
								LegoChestPrefab = val2;
							}
							else if (((Object)val2).name == "LegoLeaf")
							{
								LegoLeafPrefab = val2;
							}
							else if (((Object)val2).name == "LegoCarrot")
							{
								LegoCarrotPrefab = val2;
							}
							else
							{
								LegoCharacterPrefabs[((Object)val2).name] = val2;
							}
						}
						Log.LogInfo((object)$"Loaded bundle: {fileNameWithoutExtension} ({array.Length} prefabs)");
					}
					catch (Exception ex)
					{
						Log.LogError((object)("Error loading bundle " + Path.GetFileName(text) + ": " + ex.Message));
					}
				}
			}
			string text2 = Path.Combine(directoryName, "legomodels");
			if (Directory.Exists(text2))
			{
				ObjMeshLoader.LoadTexturesFromFolder(text2);
				LoadMultiPartModels(text2);
				LoadObjModels(text2);
			}
		}

		private void LoadRosterFromLegoSkin(string rosterDir)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (!Directory.Exists(rosterDir))
			{
				Log.LogWarning((object)("LegoSkin roster not found: " + rosterDir));
				return;
			}
			string[] directories = Directory.GetDirectories(rosterDir);
			foreach (string dir in directories)
			{
				string charName = Path.GetFileName(dir);
				if (charName.StartsWith("_") || charName == "MeshDump" || charName == "PeakReference" || charName == "Screenshots" || !File.Exists(Path.Combine(dir, "head.obj")))
				{
					continue;
				}
				Color color = GetLegoColor(charName);
				LegoCharacterParts legoCharacterParts = new LegoCharacterParts();
				legoCharacterParts.Head = Load("head.obj");
				legoCharacterParts.Torso = Load("torso.obj");
				legoCharacterParts.ArmL = Load("arms_l.obj");
				legoCharacterParts.ArmR = Load("arms_r.obj");
				legoCharacterParts.LegL = Load("legs_l.obj");
				legoCharacterParts.LegR = Load("legs_r.obj");
				string[] files = Directory.GetFiles(dir, "*.obj");
				foreach (string f in files)
				{
					string fn = Path.GetFileNameWithoutExtension(f).ToLowerInvariant();
					bool flag;
					switch (fn)
					{
					case "head":
					case "torso":
					case "arms_l":
					case "arms_r":
					case "legs_l":
					case "legs_r":
						flag = true;
						break;
					default:
						flag = false;
						break;
					}
					if (!flag && !fn.EndsWith(".precape"))
					{
						if ((Object)(object)legoCharacterParts.Hat == (Object)null && fn.StartsWith("hat"))
						{
							legoCharacterParts.Hat = MkAcc();
						}
						else if ((Object)(object)legoCharacterParts.Hair == (Object)null && fn.StartsWith("hair"))
						{
							legoCharacterParts.Hair = MkAcc();
						}
						else if ((Object)(object)legoCharacterParts.Helmet == (Object)null && (fn.StartsWith("helmet") || fn.StartsWith("mask") || fn.StartsWith("hood") || fn.StartsWith("visor") || fn.StartsWith("crown") || fn.StartsWith("cap")))
						{
							legoCharacterParts.Helmet = MkAcc();
						}
					}
					GameObject MkAcc()
					{
						//IL_001d: Unknown result type (might be due to invalid IL or missing references)
						return ObjMeshLoader.CreateGameObjectFromObj(f, charName + "_" + fn, color);
					}
				}
				legoCharacterParts.TotalHeight = ComputeTotalHeight(legoCharacterParts);
				LegoCharacterPartSets[charName] = legoCharacterParts;
				Log.LogInfo((object)$"Roster char: {charName} (head={(Object)(object)legoCharacterParts.Head != (Object)null} torso={(Object)(object)legoCharacterParts.Torso != (Object)null} hat={(Object)(object)legoCharacterParts.Hat != (Object)null} helmet={(Object)(object)legoCharacterParts.Helmet != (Object)null} hair={(Object)(object)legoCharacterParts.Hair != (Object)null} h={legoCharacterParts.TotalHeight:F1})");
				GameObject? Load(string file)
				{
					//IL_0038: Unknown result type (might be due to invalid IL or missing references)
					if (!File.Exists(Path.Combine(dir, file)))
					{
						return null;
					}
					return ObjMeshLoader.CreateGameObjectFromObj(Path.Combine(dir, file), charName + "_" + Path.GetFileNameWithoutExtension(file), color);
				}
			}
			Log.LogInfo((object)$"Loaded {LegoCharacterPartSets.Count} roster characters from LegoSkin");
		}

		private void LoadObjModels(string folder)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing reference