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? _cfgHead; private static ConfigEntry? _cfgTorso; private static ConfigEntry? _cfgArms; private static ConfigEntry? _cfgLegs; private static ConfigEntry? _cfgHat; private static ConfigEntry? _cfgHelmet; private static ConfigEntry? _cfgHair; public static LegoLoadout Current { get; private set; } = new LegoLoadout(); public static void BindConfig(ConfigFile config) { _cfgHead = config.Bind("Loadout", "Head", "", "LEGO character for head"); _cfgTorso = config.Bind("Loadout", "Torso", "", "LEGO character for torso"); _cfgArms = config.Bind("Loadout", "Arms", "", "LEGO character for both arms"); _cfgLegs = config.Bind("Loadout", "Legs", "", "LEGO character for both legs"); _cfgHat = config.Bind("Loadout", "Hat", "", "LEGO character for hat (empty = none)"); _cfgHelmet = config.Bind("Loadout", "Helmet", "", "LEGO character for helmet (empty = none)"); _cfgHair = config.Bind("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 ReplacedTrees = new HashSet(); private static readonly HashSet ReplacedBridges = new HashSet(); [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(); SkinnedMeshRenderer[] componentsInChildren2 = target.GetComponentsInChildren(); 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(legoPrefab, target.transform); val4.transform.localPosition = Vector3.zero; val4.transform.localRotation = Quaternion.identity; if (!flag) { return; } Renderer[] componentsInChildren3 = val4.GetComponentsInChildren(); 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[] 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[] 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(legoPrefab, target.transform); val5.transform.localPosition = Vector3.zero; val5.transform.localRotation = Quaternion.identity; if (!flag) { return; } Renderer[] componentsInChildren3 = val5.GetComponentsInChildren(); 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()); 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()).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.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()); 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(); ((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(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(); 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 SpawnedLegoParts = new Dictionary(); private static readonly Dictionary SpawnedDummyParts = new Dictionary(); 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 list = new List(); 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(); 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(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(); 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(); MeshRenderer component2 = part.GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null)) { Mesh val = Object.Instantiate(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(); 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 list = new List(); 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(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(); 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(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 TypeToCat = new Dictionary { { (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> _registry = new Dictionary>(); private static readonly HashSet _ourOptions = new HashSet(); 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 item in TypeToCat) { Type key = item.Key; string value = item.Value; string partType = PartTypeFor(value); List list = new List(); 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(); 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 _thumbs = new Dictionary(); 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(); 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 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(part); val5.SetActive(true); SetLayerRecursive(val5, 30); MeshFilter componentInChildren = val5.GetComponentInChildren(); 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 ReplacedTrees = new HashSet(); private static readonly HashSet ReplacedBridges = new HashSet(); private static readonly HashSet ReplacedBushes = new HashSet(); private static readonly HashSet ReplacedLuggage = new HashSet(); private static readonly HashSet ReplacedFoliage = new HashSet(); private static readonly HashSet ReplacedBingBong = new HashSet(); private static readonly HashSet ReplacedRoot = new HashSet(); private static readonly HashSet ReplacedChess = new HashSet(); private static readonly string[] ChessKeywords = new string[6] { "king", "queen", "bishop", "knight", "rook", "pawn" }; private static readonly HashSet HiddenCanopies = new HashSet(); 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(); foreach (MeshFilter val in array) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent() != (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(); foreach (MeshFilter val in array) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent() != (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(); foreach (MeshFilter val in array) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled && !((Object)(object)((Component)val).GetComponentInParent() != (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(); foreach (MeshFilter val in array) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent() != (Object)null || HasBushMaterial(component)) { continue; } string s = ((Object)val.sharedMesh).name.ToLowerInvariant(); if (ContainsAny(s, FoliageKeywords)) { LODGroup componentInParent = ((Component)val).GetComponentInParent(); 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(); foreach (MeshFilter val in array) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent() != (Object)null) { continue; } string text = ((Object)val.sharedMesh).name.ToLowerInvariant(); if (HasBushMaterial(component) || text.Contains("bush") || text.Contains("shrub")) { LODGroup componentInParent = ((Component)val).GetComponentInParent(); 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(); foreach (MeshFilter val in array) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled && !((Object)(object)((Component)val).GetComponentInParent() != (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(); 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(); foreach (MeshFilter val in array) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || !((Renderer)component).enabled || (Object)(object)((Component)val).GetComponentInParent() != (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(); 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(); 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(prefab); val3.SetActive(true); val3.AddComponent(); MeshFilter componentInChildren = val3.GetComponentInChildren(); 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(); 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(); foreach (MeshRenderer val in componentsInChildren) { ((Renderer)val).enabled = false; } SkinnedMeshRenderer[] componentsInChildren2 = target.GetComponentsInChildren(); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { ((Renderer)val2).enabled = false; } GameObject val3 = Object.Instantiate(legoPrefab, target.transform); val3.SetActive(true); val3.AddComponent(); val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; MeshFilter component = val3.GetComponent(); 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 LoadedTextures = new Dictionary(); 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 materialNames; string mtllib; return LoadObjMesh(path, out materialNames, out mtllib); } public static Mesh? LoadObjMesh(string path, out List 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(); mtllib = null; if (!File.Exists(path)) { return null; } List matNames = new List(); List rawV = new List(); List rawVN = new List(); List rawVT = new List(); List vertices = new List(); List normals = new List(); List uvs = new List(); Dictionary<(int, int, int), int> combo = new Dictionary<(int, int, int), int>(); List> subTris = new List>(); Dictionary subByName = new Dictionary(); List 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 list = new List(); 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()); 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 ParseMtlColors(string mtlPath) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); 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 ParseMtlTextures(string mtlPath) { Dictionary dictionary = new Dictionary(); 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 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(); val4.mesh = val; MeshRenderer val5 = val3.AddComponent(); string directoryName = Path.GetDirectoryName(path); string mtlPath = Path.Combine(directoryName, mtllib ?? (Path.GetFileNameWithoutExtension(path) + ".mtl")); Dictionary dictionary = ParseMtlColors(mtlPath); Dictionary 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 LoadedBundles = new Dictionary(); internal static readonly Dictionary LegoCharacterPrefabs = new Dictionary(); internal static readonly Dictionary LegoCharacterPartSets = new Dictionary(); 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 LegoMinifigPrefabs = new List(); internal const bool PassportEnabled = false; internal static ConfigEntry ReplaceOutfits = null; internal static ConfigEntry ReplaceTrees = null; internal static ConfigEntry ReplaceBridges = null; internal static ConfigEntry ReplaceBushes = null; internal static ConfigEntry BushScale = null; internal static ConfigEntry ReplaceLuggage = null; internal static ConfigEntry ChestScale = null; internal static ConfigEntry ReplaceFoliage = null; internal static ConfigEntry LeafScale = null; internal static ConfigEntry ReplaceBingBong = null; internal static ConfigEntry MinikitScale = null; internal static ConfigEntry ReplaceMedicinalRoot = null; internal static ConfigEntry CarrotScale = null; internal static ConfigEntry ReplaceChess = null; private static readonly Dictionary CharacterColors = new Dictionary { { "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("General", "ReplaceOutfits", true, "Replace character outfits with LEGO models"); ReplaceTrees = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceTrees", true, "Replace trees with LEGO tree model"); ReplaceBridges = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceBridges", true, "Replace bridges with LEGO bridge model"); ReplaceBushes = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceBushes", true, "Replace bushes with the bush model"); BushScale = ((BaseUnityPlugin)this).Config.Bind("General", "BushScale", 1.6f, "Bush size multiplier (1 = match original bush size)"); ReplaceLuggage = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceLuggage", true, "Replace luggage with the LEGO treasure chest"); ChestScale = ((BaseUnityPlugin)this).Config.Bind("General", "ChestScale", 1f, "Chest size multiplier (1 = match original luggage size)"); ReplaceFoliage = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceFoliage", true, "Replace leftover leaf/grass meshes (ferns, sprouts, grass) with the LEGO leaf"); LeafScale = ((BaseUnityPlugin)this).Config.Bind("General", "LeafScale", 1f, "Leaf size multiplier (1 = match original foliage size)"); ReplaceBingBong = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceBingBong", true, "Replace the Bing Bong item with the LEGO minikit canister"); MinikitScale = ((BaseUnityPlugin)this).Config.Bind("General", "MinikitScale", 1f, "Minikit canister size multiplier (1 = match Bing Bong size)"); ReplaceChess = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceChess", true, "Replace chess pieces with the LEGO minifig skins (small)"); ReplaceMedicinalRoot = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceMedicinalRoot", true, "Replace the medicinal root item with the LEGO carrot"); CarrotScale = ((BaseUnityPlugin)this).Config.Bind("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(); 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[] 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 references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) string[] files = Directory.GetFiles(folder, "*.obj"); Log.LogInfo((object)$"Loading {files.Length} OBJ models from {folder}"); Dictionary dictionary = new Dictionary { { "Batman", new Color(0.15f, 0.15f, 0.15f) }, { "DarthVader", new Color(0.1f, 0.1f, 0.12f) }, { "HarleyQuinn", new Color(0.9f, 0.2f, 0.3f) }, { "R2D2", new Color(0.8f, 0.85f, 0.9f) }, { "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) } }; string[] array = files; foreach (string path in array) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); Color color = (dictionary.ContainsKey(fileNameWithoutExtension) ? dictionary[fileNameWithoutExtension] : RandomColorFromName(fileNameWithoutExtension)); GameObject val = ObjMeshLoader.CreateGameObjectFromObj(path, fileNameWithoutExtension, color); switch (fileNameWithoutExtension) { case "LegoTree": LegoTreePrefab = val; break; case "LegoBridge": LegoBridgePrefab = val; break; case "LegoBush": LegoBushPrefab = val; break; case "LegoChest": LegoChestPrefab = val; break; case "LegoLeaf": LegoLeafPrefab = val; break; case "LegoCarrot": LegoCarrotPrefab = val; break; default: if (fileNameWithoutExtension.StartsWith("Minifig_")) { LegoMinifigPrefabs.Add(val); } else { LegoCharacterPrefabs[fileNameWithoutExtension] = val; } break; } Log.LogInfo((object)(" OBJ loaded: " + fileNameWithoutExtension)); } } private void LoadMultiPartModels(string folder) { //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_00b0: Unknown result type (might be due to invalid IL or missing references) string[] directories = Directory.GetDirectories(folder); foreach (string text in directories) { string fileName = Path.GetFileName(text); LegoCharacterParts legoCharacterParts = new LegoCharacterParts(); string[] array = new string[7] { "head", "torso", "armR", "armL", "legR", "legL", "cape" }; ObjMeshLoader.LoadTexturesFromFolder(text); string[] array2 = array; foreach (string text2 in array2) { string path = Path.Combine(text, text2 + ".obj"); if (File.Exists(path)) { Color legoColor = GetLegoColor(fileName); GameObject val = ObjMeshLoader.CreateGameObjectFromObj(path, fileName + "_" + text2, legoColor); switch (text2) { case "head": legoCharacterParts.Head = val; break; case "torso": legoCharacterParts.Torso = val; break; case "armR": legoCharacterParts.ArmR = val; break; case "armL": legoCharacterParts.ArmL = val; break; case "legR": legoCharacterParts.LegR = val; break; case "legL": legoCharacterParts.LegL = val; break; case "cape": legoCharacterParts.Cape = val; break; } } } legoCharacterParts.TotalHeight = ComputeTotalHeight(legoCharacterParts); LegoCharacterPartSets[fileName] = legoCharacterParts; Log.LogInfo((object)$"Loaded multi-part character: {fileName} (height={legoCharacterParts.TotalHeight:F1})"); } } private static float ComputeTotalHeight(LegoCharacterParts parts) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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_00ab: 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_012a: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) float num = float.MaxValue; float num2 = float.MinValue; string[] array = new string[5] { "torso", "armR", "armL", "legR", "legL" }; foreach (string partType in array) { GameObject part = parts.GetPart(partType); if ((Object)(object)part == (Object)null) { continue; } MeshFilter component = part.GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null)) { Bounds bounds = component.sharedMesh.bounds; if (((Bounds)(ref bounds)).min.y < num) { num = ((Bounds)(ref bounds)).min.y; } if (((Bounds)(ref bounds)).max.y > num2) { num2 = ((Bounds)(ref bounds)).max.y; } } } GameObject head = parts.Head; if ((Object)(object)head != (Object)null) { MeshFilter component2 = head.GetComponent(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.sharedMesh != (Object)null) { Bounds bounds2 = component2.sharedMesh.bounds; if (((Bounds)(ref bounds2)).max.y > num2) { bounds2 = component2.sharedMesh.bounds; num2 = ((Bounds)(ref bounds2)).max.y; } } } return num2 - num; } internal static Color GetLegoColor(string name) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (CharacterColors.TryGetValue(name, out var value)) { return value; } int hashCode = name.GetHashCode(); return new Color((float)((hashCode >> 16) & 0xFF) / 255f, (float)((hashCode >> 8) & 0xFF) / 255f, (float)(hashCode & 0xFF) / 255f); } private static Color RandomColorFromName(string name) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetLegoColor(name); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } foreach (AssetBundle value in LoadedBundles.Values) { if (value != null) { value.Unload(false); } } } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } }