Decompiled source of Custom Holsters v1.0.0
Mods/CustomHolsters.dll
Decompiled 13 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using BoneLib; using BoneLib.BoneMenu; using BoneLib.Notifications; using CustomHolsters; using CustomHolsters.Compat; using CustomHolsters.Holsters; using CustomHolsters.Layouts; using CustomHolsters.Menu; using CustomHolsters.Preview; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.Warehouse; using Il2CppSLZ.VRMK; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "Custom Holsters", "1.0.0", "TMLMedia", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("CustomHolsters")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Custom Holsters")] [assembly: AssemblyTitle("Custom Holsters")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CustomHolsters { public class Core : MelonMod { private object _setupRoutine; public static Core Instance { get; private set; } public static Instance Log => ((MelonBase)Instance).LoggerInstance; public override void OnInitializeMelon() { Instance = this; Settings.Init(); LayoutManager.Init(); Hooking.OnLevelLoaded += OnLevelLoaded; Hooking.OnLevelUnloaded += OnLevelUnloaded; Log.Msg("Custom Holsters 1.0.0 loaded. Layouts: " + LayoutManager.LayoutDir); } public override void OnLateInitializeMelon() { FusionCompat.Init(); BuildMenuSafe(); } private static void BuildMenuSafe() { try { HolsterMenu.Build(); } catch (Exception ex) { Log.Error("Failed to build BoneMenu page: " + ex); } } private void OnLevelLoaded(LevelInfo info) { BuildMenuSafe(); ScheduleSetup(avatarChanged: false); } private void OnLevelUnloaded() { LayoutManager.FlushPendingSave(); AvatarPreview.Destroy(); HolsterApplier.ClearQueue(); HolsterRegistry.Clear(restore: false); AnchorResolver.Clear(); } internal static void OnLocalAvatarSwitched() { if (Instance != null) { Instance.ScheduleSetup(avatarChanged: true); } } public void ScheduleSetup(bool avatarChanged) { if (_setupRoutine != null) { MelonCoroutines.Stop(_setupRoutine); } _setupRoutine = MelonCoroutines.Start(SetupRoutine(avatarChanged)); } private IEnumerator SetupRoutine(bool avatarChanged) { HolsterApplier.Suspended = true; for (int i = 0; i < 3; i++) { yield return null; } float until = Time.realtimeSinceStartup + 0.35f; while (Time.realtimeSinceStartup < until) { yield return null; } RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null) { HolsterApplier.Suspended = false; _setupRoutine = null; yield break; } try { if ((Object)(object)HolsterRegistry.Rig != (Object)(object)rigManager) { HolsterRegistry.Scan(rigManager); } else { foreach (HolsterSlot slot in HolsterRegistry.Slots) { if (slot.IsValid && slot.Overridden) { slot.RestoreVanilla(); } } try { if ((Object)(object)rigManager.avatar != (Object)null && (Object)(object)rigManager.physicsRig != (Object)null) { rigManager.physicsRig.SetBodySlot(rigManager.avatar); } } catch (Exception) { } HolsterRegistry.RecaptureVanilla(); } AnchorResolver.Calibrate(rigManager); string text = ""; string title = ""; try { text = ((ScannableReference)rigManager.AvatarCrate).Barcode.ID; title = (((Object)(object)((CrateReferenceT<AvatarCrate>)(object)rigManager.AvatarCrate).Crate != (Object)null) ? ((Scannable)((CrateReferenceT<AvatarCrate>)(object)rigManager.AvatarCrate).Crate).Title : text); } catch (Exception) { } LayoutManager.OnAvatarChanged(text, title); HolsterApplier.OnLayoutReplaced(); } catch (Exception ex3) { Log.Error("Holster setup failed: " + ex3); } HolsterApplier.Suspended = false; HolsterMenu.OnRigReady(); if (AvatarPreview.IsVisible) { AvatarPreview.Rebuild(); } _setupRoutine = null; } public override void OnUpdate() { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager != (Object)null && (Object)(object)rigManager != (Object)(object)HolsterRegistry.Rig && _setupRoutine == null) { HolsterRegistry.Clear(restore: false); ScheduleSetup(avatarChanged: false); } HolsterApplier.Tick(processQueue: true); LayoutManager.Tick(); HolsterMenu.Tick(); } public override void OnFixedUpdate() { HolsterApplier.Tick(processQueue: false); } public override void OnLateUpdate() { HolsterApplier.Tick(processQueue: false); AvatarPreview.Tick(); } public override void OnApplicationQuit() { LayoutManager.FlushPendingSave(); } } [HarmonyPatch(typeof(RigManager), "SwitchAvatar")] internal static class SwitchAvatarPatch { [HarmonyPostfix] private static void Postfix(RigManager __instance) { try { if ((Object)(object)__instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.RigManager) { Core.OnLocalAvatarSwitched(); } } catch (Exception) { } } } public static class ModInfo { public const string Name = "Custom Holsters"; public const string InternalName = "CustomHolsters"; public const string Version = "1.0.0"; public const string Author = "TMLMedia"; public const string DataFolderName = "CustomHolsters"; } public static class Settings { private static MelonPreferences_Category _category; public static MelonPreferences_Entry<bool> Enabled; public static MelonPreferences_Entry<string> DefaultLayout; public static MelonPreferences_Entry<bool> AutoLoadAvatarLayouts; public static MelonPreferences_Entry<bool> AutoSave; public static MelonPreferences_Entry<bool> ReseatHolsteredItems; public static MelonPreferences_Entry<bool> ShowLiveGizmo; public static MelonPreferences_Entry<bool> CopyHandRotation; public static MelonPreferences_Entry<float> PreviewHeight; public static void Init() { _category = MelonPreferences.CreateCategory("CustomHolsters", "Custom Holsters"); Enabled = _category.CreateEntry<bool>("Enabled", true, "Enabled", "Master switch. When off, every holster returns to its vanilla BONELAB position.", false, false, (ValueValidator)null, (string)null); DefaultLayout = _category.CreateEntry<string>("DefaultLayout", "Default", "Default Layout", "Layout used for any avatar that has no layout bound to it.", false, false, (ValueValidator)null, (string)null); AutoLoadAvatarLayouts = _category.CreateEntry<bool>("AutoLoadAvatarLayouts", true, "Auto-Load Avatar Layouts", "Automatically switch to the layout bound to an avatar when you change into it.", false, false, (ValueValidator)null, (string)null); AutoSave = _category.CreateEntry<bool>("AutoSave", true, "Auto-Save", "Save the active layout automatically a moment after each edit.", false, false, (ValueValidator)null, (string)null); ReseatHolsteredItems = _category.CreateEntry<bool>("ReseatHolsteredItems", true, "Re-seat Holstered Items", "After moving a holster, re-insert whatever it holds so the item jumps to the new spot. Disabled automatically inside Fusion lobbies.", false, false, (ValueValidator)null, (string)null); ShowLiveGizmo = _category.CreateEntry<bool>("ShowLiveGizmo", true, "Show Live Gizmo", "Draw a small marker on the real holster you are editing.", false, false, (ValueValidator)null, (string)null); CopyHandRotation = _category.CreateEntry<bool>("CopyHandRotation", false, "Copy Hand Rotation", "When placing a holster at your hand, also copy the hand's rotation.", false, false, (ValueValidator)null, (string)null); PreviewHeight = _category.CreateEntry<float>("PreviewHeight", 0.6f, "Preview Height", "Height in meters of the 3D avatar preview figure.", false, false, (ValueValidator)null, (string)null); } public static void Save() { if (_category != null) { _category.SaveToFile(false); } } } } namespace CustomHolsters.Preview { public static class AvatarPreview { private sealed class Marker { public GameObject Root; public Renderer Ball; public int ColorKey = -1; } private static readonly Color SelectedColor = new Color(1f, 0.85f, 0.1f, 1f); private static readonly Color MovedColor = new Color(0.1f, 0.85f, 1f, 1f); private static readonly Color VanillaColor = new Color(0.85f, 0.85f, 0.85f, 1f); private static readonly Color AmmoColor = new Color(1f, 0.5f, 0.15f, 1f); private static readonly Color DiscColor = new Color(0.15f, 0.17f, 0.2f, 1f); private static GameObject _root; private static Transform _turntable; private static Transform _model; private static GameObject _liveGizmo; private static Transform _liveGizmoTarget; private static readonly List<Mesh> _bakedMeshes = new List<Mesh>(); private static readonly Dictionary<string, Marker> _markers = new Dictionary<string, Marker>(); private static readonly Dictionary<string, Vector3> _vanillaPos = new Dictionary<string, Vector3>(); private static readonly Dictionary<string, Quaternion> _vanillaRot = new Dictionary<string, Quaternion>(); private static readonly int AnchorCount = Enum.GetValues(typeof(BodyAnchor)).Length; private static readonly Vector3[] _anchorPos = (Vector3[])(object)new Vector3[AnchorCount]; private static readonly Quaternion[] _anchorRot = (Quaternion[])(object)new Quaternion[AnchorCount]; private static readonly bool[] _anchorValid = new bool[AnchorCount]; private static float _avatarHeight = 1.76f; private static float _modelScale = 1f; private static float _yaw; private static float _pitch; public static bool AutoSpin; public static string SelectedId; public static bool IsVisible => (Object)(object)_root != (Object)null; public static float Yaw => _yaw; public static void SetVisible(bool visible) { if (visible) { Rebuild(); } else { Destroy(); } } public static void Rebuild() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_0073: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) Destroy(); RigManager rigManager = Player.RigManager; Avatar val = (((Object)(object)rigManager != (Object)null) ? rigManager.avatar : null); if ((Object)(object)val == (Object)null || !AnchorResolver.IsCalibrated) { HolsterMenuNotify("Load into a level with an avatar first."); return; } try { Transform transform = ((Component)val).transform; _avatarHeight = ((val.height > 0.1f) ? val.height : 1.76f); _root = new GameObject("[Custom Holsters] Preview"); _turntable = new GameObject("Turntable").transform; _turntable.SetParent(_root.transform, false); _model = new GameObject("Model").transform; _model.SetParent(_turntable, false); BakeRenderers(transform); BakeAnchorsAndVanilla(transform); BuildDisc(); BuildMarkers(); _modelScale = Mathf.Clamp(Settings.PreviewHeight.Value, 0.15f, 2.5f) / _avatarHeight; _model.localScale = Vector3.one * _modelScale; _model.localPosition = new Vector3(0f, (0f - _avatarHeight) * 0.5f * _modelScale, 0f); Recenter(); ApplyRotation(); UpdateMarkers(); } catch (Exception ex) { Core.Log.Error("Failed to build avatar preview: " + ex); Destroy(); } } public static void Destroy() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } _root = null; _turntable = null; _model = null; foreach (Mesh bakedMesh in _bakedMeshes) { if ((Object)(object)bakedMesh != (Object)null) { Object.Destroy((Object)(object)bakedMesh); } } _bakedMeshes.Clear(); _markers.Clear(); _vanillaPos.Clear(); _vanillaRot.Clear(); DestroyLiveGizmo(); } public static void Recenter() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_009c: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null)) { Transform head = Player.Head; Vector3 val = (((Object)(object)head != (Object)null) ? head.position : Vector3.zero); Vector3 val2 = (((Object)(object)head != (Object)null) ? Vector3.ProjectOnPlane(head.forward, Vector3.up) : Vector3.forward); if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = Vector3.forward; } ((Vector3)(ref val2)).Normalize(); Vector3 val3 = val + val2 * 0.6f + Vector3.down * 0.3f; _root.transform.SetPositionAndRotation(val3, Quaternion.LookRotation(-val2, Vector3.up)); } } public static void Rotate(float degrees) { _yaw = HolsterApplier.Wrap(_yaw + degrees); ApplyRotation(); } public static void Tilt(float degrees) { _pitch = Mathf.Clamp(_pitch + degrees, -75f, 75f); ApplyRotation(); } public static void SetView(float yaw) { _yaw = yaw; _pitch = 0f; ApplyRotation(); } public static void Tick() { if ((Object)(object)_root == (Object)null) { DestroyLiveGizmo(); return; } if (AutoSpin) { _yaw = HolsterApplier.Wrap(_yaw + 30f * Time.deltaTime); ApplyRotation(); } try { UpdateMarkers(); UpdateLiveGizmo(); } catch (Exception) { Destroy(); } } private static void BakeRenderers(Transform src) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0087: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: 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) Quaternion val = Quaternion.Inverse(src.rotation); Vector3 position = src.position; foreach (SkinnedMeshRenderer componentsInChild in ((Component)src).GetComponentsInChildren<SkinnedMeshRenderer>(false)) { if (!((Object)(object)componentsInChild == (Object)null) && ((Renderer)componentsInChild).enabled && !((Object)(object)componentsInChild.sharedMesh == (Object)null)) { Mesh val2 = new Mesh(); componentsInChild.BakeMesh(val2, true); _bakedMeshes.Add(val2); Transform transform = ((Component)componentsInChild).transform; AddStatic("Baked " + ((Object)componentsInChild).name, val2, ((Renderer)componentsInChild).sharedMaterials, val * (transform.position - position), val * transform.rotation, Vector3.one); } } foreach (MeshRenderer componentsInChild2 in ((Component)src).GetComponentsInChildren<MeshRenderer>(false)) { if (!((Object)(object)componentsInChild2 == (Object)null) && ((Renderer)componentsInChild2).enabled) { MeshFilter component = ((Component)componentsInChild2).GetComponent<MeshFilter>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null)) { Transform transform2 = ((Component)componentsInChild2).transform; AddStatic("Static " + ((Object)componentsInChild2).name, component.sharedMesh, ((Renderer)componentsInChild2).sharedMaterials, val * (transform2.position - position), val * transform2.rotation, transform2.lossyScale); } } } } private static void AddStatic(string name, Mesh mesh, Il2CppReferenceArray<Material> materials, Vector3 localPos, Quaternion localRot, Vector3 localScale) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(_model, false); val.transform.localPosition = localPos; val.transform.localRotation = localRot; val.transform.localScale = localScale; val.layer = 0; val.AddComponent<MeshFilter>().sharedMesh = mesh; MeshRenderer obj = val.AddComponent<MeshRenderer>(); ((Renderer)obj).sharedMaterials = materials; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj).receiveShadows = false; if (materials != null && ((Il2CppArrayBase<Material>)(object)materials).Length > 0 && (Object)(object)((Il2CppArrayBase<Material>)(object)materials)[0] != (Object)null) { PreviewMaterials.SetFallbackShader(((Il2CppArrayBase<Material>)(object)materials)[0].shader); } } private static void BakeAnchorsAndVanilla(Transform src) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.Inverse(src.rotation); Vector3 position = src.position; foreach (BodyAnchor value in Enum.GetValues(typeof(BodyAnchor))) { int num = (int)value; _anchorValid[num] = AnchorResolver.TryGetFrame(value, out var position2, out var rotation); if (_anchorValid[num]) { _anchorPos[num] = val * (position2 - position); _anchorRot[num] = val * rotation; } } foreach (HolsterSlot slot in HolsterRegistry.Slots) { if (slot.IsValid) { _vanillaPos[slot.Id] = val * (slot.VanillaWorldPosition - position); _vanillaRot[slot.Id] = val * slot.VanillaWorldRotation; } } } private static void BuildDisc() { //IL_0031: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Primitive((PrimitiveType)2, "Turntable Disc", _model); float num = _avatarHeight * 0.45f; obj.transform.localPosition = new Vector3(0f, -0.01f, 0f); obj.transform.localScale = new Vector3(num, 0.008f, num); SetColor(obj.GetComponent<Renderer>(), DiscColor); GameObject obj2 = Primitive((PrimitiveType)3, "Front Notch", _model); obj2.transform.localPosition = new Vector3(0f, 0f, num * 0.5f); obj2.transform.localScale = new Vector3(0.04f, 0.012f, 0.06f) * (_avatarHeight / 1.76f); SetColor(obj2.GetComponent<Renderer>(), SelectedColor); } private static void BuildMarkers() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) foreach (HolsterSlot slot in HolsterRegistry.Slots) { if (slot.IsValid && !_markers.ContainsKey(slot.Id)) { Marker marker = new Marker(); marker.Root = new GameObject("Marker " + slot.Id); marker.Root.transform.SetParent(_model, false); GameObject val = Primitive((PrimitiveType)0, "Ball", marker.Root.transform); marker.Ball = val.GetComponent<Renderer>(); AddAxis(marker.Root.transform, Vector3.right, new Color(1f, 0.25f, 0.25f, 1f)); AddAxis(marker.Root.transform, Vector3.up, new Color(0.3f, 1f, 0.3f, 1f)); AddAxis(marker.Root.transform, Vector3.forward, new Color(0.3f, 0.5f, 1f, 1f)); _markers[slot.Id] = marker; } } } private static void AddAxis(Transform parent, Vector3 dir, Color color) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0094: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Primitive((PrimitiveType)3, "Axis", parent); obj.transform.localPosition = dir * 0.9f; Vector3 localScale = default(Vector3); ((Vector3)(ref localScale))..ctor(0.15f, 0.15f, 0.15f); if (dir.x != 0f) { localScale.x = 1.8f; } if (dir.y != 0f) { localScale.y = 1.8f; } if (dir.z != 0f) { localScale.z = 1.8f; } obj.transform.localScale = localScale; SetColor(obj.GetComponent<Renderer>(), color); } private static void ApplyRotation() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_turntable != (Object)null) { _turntable.localRotation = Quaternion.Euler(_pitch, _yaw, 0f); } } private static void UpdateMarkers() { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: 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) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: 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_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: 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_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) HolsterLayout current = LayoutManager.Current; float offsetScale = HolsterApplier.OffsetScale; float num = 0.035f * (_avatarHeight / 1.76f); foreach (HolsterSlot slot in HolsterRegistry.Slots) { if (_markers.TryGetValue(slot.Id, out var value) && !((Object)(object)value.Root == (Object)null)) { HolsterPlacement holsterPlacement = ((current != null && Settings.Enabled.Value) ? current.Get(slot.Id) : null); bool flag = holsterPlacement != null && holsterPlacement.Moved && _anchorValid[(int)holsterPlacement.Anchor]; Vector3 value2; Quaternion value3; if (flag) { int anchor = (int)holsterPlacement.Anchor; value2 = _anchorPos[anchor] + _anchorRot[anchor] * (holsterPlacement.Position.ToVector3() * offsetScale); value3 = _anchorRot[anchor] * Quaternion.Euler(holsterPlacement.Rotation.ToVector3()); } else if (!_vanillaPos.TryGetValue(slot.Id, out value2) || !_vanillaRot.TryGetValue(slot.Id, out value3)) { value.Root.SetActive(false); continue; } bool flag2 = slot.Id == SelectedId; value.Root.SetActive(true); value.Root.transform.localPosition = value2; value.Root.transform.localRotation = value3; value.Root.transform.localScale = Vector3.one * num * (flag2 ? 1.7f : 1f); Color color = (flag2 ? SelectedColor : (flag ? MovedColor : (slot.IsAmmoPouch ? AmmoColor : VanillaColor))); int num2 = ((!flag2) ? (flag ? 1 : (slot.IsAmmoPouch ? 2 : 3)) : 0); if (value.ColorKey != num2) { value.ColorKey = num2; SetColor(value.Ball, color); } } } } private static void UpdateLiveGizmo() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00ab: 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_00d8: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0189: 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) HolsterSlot holsterSlot = (string.IsNullOrEmpty(SelectedId) ? null : HolsterRegistry.Find(SelectedId)); if (!Settings.ShowLiveGizmo.Value || holsterSlot == null || !holsterSlot.IsValid) { DestroyLiveGizmo(); return; } if ((Object)(object)_liveGizmo == (Object)null || (Object)(object)_liveGizmoTarget != (Object)(object)holsterSlot.Target) { DestroyLiveGizmo(); _liveGizmoTarget = holsterSlot.Target; _liveGizmo = new GameObject("[Custom Holsters] Live Gizmo"); _liveGizmo.transform.SetParent(holsterSlot.Target, false); SetColor(Primitive((PrimitiveType)0, "Ball", _liveGizmo.transform).GetComponent<Renderer>(), SelectedColor); AddAxis(_liveGizmo.transform, Vector3.right, new Color(1f, 0.25f, 0.25f, 1f)); AddAxis(_liveGizmo.transform, Vector3.up, new Color(0.3f, 1f, 0.3f, 1f)); AddAxis(_liveGizmo.transform, Vector3.forward, new Color(0.3f, 0.5f, 1f, 1f)); } float num = Mathf.Max(holsterSlot.Target.lossyScale.x, 0.0001f); _liveGizmo.transform.localPosition = Vector3.zero; _liveGizmo.transform.localRotation = Quaternion.identity; _liveGizmo.transform.localScale = Vector3.one * (0.03f / num); } private static void DestroyLiveGizmo() { if ((Object)(object)_liveGizmo != (Object)null) { Object.Destroy((Object)(object)_liveGizmo); } _liveGizmo = null; _liveGizmoTarget = null; } private static GameObject Primitive(PrimitiveType type, string name, Transform parent) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive(type); ((Object)obj).name = name; Collider component = obj.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } obj.transform.SetParent(parent, false); obj.layer = 0; Renderer component2 = obj.GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { component2.shadowCastingMode = (ShadowCastingMode)0; component2.receiveShadows = false; } return obj; } private static void SetColor(Renderer renderer, Color color) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)renderer == (Object)null)) { Material val = PreviewMaterials.Get(color); if ((Object)(object)val != (Object)null) { renderer.sharedMaterial = val; } } } private static void HolsterMenuNotify(string message) { HolsterMenu.Notify(message, warning: true); } } public static class PreviewMaterials { private static readonly Dictionary<int, Material> _cache = new Dictionary<int, Material>(); private static Shader _shader; private static Shader _fallback; private static readonly string[] ShaderNames = new string[4] { "Universal Render Pipeline/Unlit", "Universal Render Pipeline/Simple Lit", "Universal Render Pipeline/Lit", "Unlit/Color" }; public static void SetFallbackShader(Shader shader) { if ((Object)(object)shader != (Object)null && (Object)(object)_fallback == (Object)null) { _fallback = shader; } } public static Material Get(Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) int key = ((int)(color.r * 255f) << 24) | ((int)(color.g * 255f) << 16) | ((int)(color.b * 255f) << 8) | (int)(color.a * 255f); if (_cache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } Shader val = FindShader(); if ((Object)(object)val == (Object)null) { return null; } value = new Material(val); ((Object)value).hideFlags = (HideFlags)32; if (value.HasProperty("_BaseColor")) { value.SetColor("_BaseColor", color); } if (value.HasProperty("_Color")) { value.SetColor("_Color", color); } if (value.HasProperty("_EmissionColor")) { value.EnableKeyword("_EMISSION"); value.SetColor("_EmissionColor", color * 0.6f); } _cache[key] = value; return value; } private static Shader FindShader() { if ((Object)(object)_shader != (Object)null) { return _shader; } string[] shaderNames = ShaderNames; for (int i = 0; i < shaderNames.Length; i++) { Shader val = Shader.Find(shaderNames[i]); if ((Object)(object)val != (Object)null) { _shader = val; return val; } } return _fallback; } } } namespace CustomHolsters.Menu { public static class HolsterMenu { private enum StepSize { Fine, Normal, Coarse } private static readonly Color Accent = new Color(0.35f, 0.85f, 1f, 1f); private static readonly Color Gold = new Color(1f, 0.85f, 0.2f, 1f); private static readonly Color Soft = new Color(0.8f, 0.8f, 0.85f, 1f); private static readonly Color Muted = new Color(0.55f, 0.55f, 0.6f, 1f); private static readonly Color Good = new Color(0.4f, 1f, 0.55f, 1f); private static readonly Color Danger = new Color(1f, 0.4f, 0.35f, 1f); private static readonly Color PosColor = new Color(0.55f, 0.9f, 1f, 1f); private static readonly Color RotColor = new Color(1f, 0.7f, 0.95f, 1f); private static bool _built; private static Page _root; private static Page _editor; private static Page _choose; private static Page _anchors; private static Page _quick; private static Page _preview; private static Page _layouts; private static Page _load; private static Page _settings; private static FunctionElement _status; private static FunctionElement _selected; private static FunctionElement _state; private static FunctionElement _anchorButton; private static FunctionElement _stepButton; private static FunctionElement _layoutLabel; private static FunctionElement _avatarLabel; private static FunctionElement _fusionLabel; private static FloatElement _px; private static FloatElement _py; private static FloatElement _pz; private static FloatElement _rx; private static FloatElement _ry; private static FloatElement _rz; private static FloatElement _grab; private static FloatElement _globalGrab; private static FloatElement _previewSize; private static BoolElement _enabled; private static BoolElement _scaleWithAvatar; private static BoolElement _previewToggle; private static int _selectedIndex; private static StepSize _step = StepSize.Normal; private static string _pendingName = "My Layout"; private static float _countdownEnd = -1f; private static int _countdownShown; private static string _countdownMessage; private static Action _countdownAction; private static float _nextStatusRefresh; private static HolsterSlot Selected { get { int count = HolsterRegistry.Slots.Count; if (count == 0) { return null; } _selectedIndex = (_selectedIndex % count + count) % count; HolsterSlot holsterSlot = HolsterRegistry.Slots[_selectedIndex]; if (!holsterSlot.IsValid) { return null; } return holsterSlot; } } public static void Build() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if (!_built && Page.Root != null) { _built = true; _root = Page.Root.CreatePage("Custom Holsters", Accent, 0, true); TrySetLogo(_root); _enabled = _root.CreateBool("Enabled", Good, Settings.Enabled.Value, (Action<bool>)delegate(bool v) { Settings.Enabled.Value = v; Settings.Save(); HolsterApplier.MarkGrabDirty(); }); ((Element)_enabled).ElementTooltip = "Master switch. Off returns every holster to its vanilla spot."; _status = _root.CreateFunction("Status: waiting for a level", Muted, (Action)delegate { RefreshStatus(); }); _editor = _root.CreatePage("Holster Editor", Gold, 0, true); _preview = _root.CreatePage("3D Avatar Preview", Accent, 0, true); _layouts = _root.CreatePage("Layouts", Good, 0, true); _settings = _root.CreatePage("Settings & Resets", Soft, 0, true); BuildEditor(); BuildPreview(); BuildLayouts(); BuildSettings(); LayoutManager.LayoutSwitched += delegate { RefreshAll(); RebuildLoadList(); }; LayoutManager.LibraryChanged += delegate { RebuildLoadList(); RefreshLayoutLabels(); }; RebuildLoadList(); RefreshAll(); } } private static void BuildEditor() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_052b: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_04d6: Unknown result type (might be due to invalid IL or missing references) //IL_05c7: Unknown result type (might be due to invalid IL or missing references) //IL_05fb: Unknown result type (might be due to invalid IL or missing references) _selected = _editor.CreateFunction("Holster: (load a level)", Gold, (Action)delegate { SelectOffset(1); }); ((Element)_selected).ElementTooltip = "Press to cycle to the next holster."; _editor.CreateFunction("< Previous Holster", Soft, (Action)delegate { SelectOffset(-1); }); _editor.CreateFunction("Next Holster >", Soft, (Action)delegate { SelectOffset(1); }); _choose = _editor.CreatePage("Choose Holster...", Soft, 0, true); _state = _editor.CreateFunction("State: -", Muted, (Action)delegate { }); _anchors = _editor.CreatePage("Attach To (body part)", Accent, 0, false); foreach (BodyAnchor value in Enum.GetValues(typeof(BodyAnchor))) { BodyAnchor a = value; _anchors.CreateFunction(BodyAnchorUtil.Pretty(a), Soft, (Action)delegate { HolsterSlot selected = Selected; if (selected != null) { HolsterApplier.Reanchor(selected, a); RefreshEditor(); Menu.OpenPage(_editor); } }); } _anchorButton = _editor.CreateFunction("Attach To: -", Accent, (Action)delegate { Menu.OpenPage(_anchors); }); ((Element)_anchorButton).ElementTooltip = "Choose which body part this holster follows. The holster stays where it is; only its anchor changes."; _stepButton = _editor.CreateFunction("", Soft, (Action)CycleStep); ((Element)_stepButton).ElementTooltip = "How far each +/- press moves or rotates the holster."; _px = _editor.CreateFloat("Left / Right (cm)", PosColor, 0f, 1f, -150f, 150f, (Action<float>)delegate(float v) { SetPosition(0, v); }); _py = _editor.CreateFloat("Down / Up (cm)", PosColor, 0f, 1f, -150f, 150f, (Action<float>)delegate(float v) { SetPosition(1, v); }); _pz = _editor.CreateFloat("Back / Forward (cm)", PosColor, 0f, 1f, -150f, 150f, (Action<float>)delegate(float v) { SetPosition(2, v); }); _rx = _editor.CreateFloat("Pitch (deg)", RotColor, 0f, 5f, -180f, 180f, (Action<float>)delegate(float v) { SetRotation(0, v); }); _ry = _editor.CreateFloat("Yaw (deg)", RotColor, 0f, 5f, -180f, 180f, (Action<float>)delegate(float v) { SetRotation(1, v); }); _rz = _editor.CreateFloat("Roll (deg)", RotColor, 0f, 5f, -180f, 180f, (Action<float>)delegate(float v) { SetRotation(2, v); }); ((Element)_px).ElementTooltip = "Offsets are relative to the chosen body part, measured for a 1.76 m avatar and scaled to yours."; _grab = _editor.CreateFloat("Grab Radius (x)", Good, 1f, 0.1f, 0.1f, 5f, (Action<float>)SetGrabRadius); ((Element)_grab).ElementTooltip = "How close your hand/item must be to use this holster. 1 = vanilla."; _quick = _editor.CreatePage("Quick Place...", Gold, 0, true); foreach (string item in Presets.Groups()) { Page val = _quick.CreatePage(item, Soft, 0, true); foreach (HolsterPreset item2 in Presets.All) { if (item2.Group != item) { continue; } HolsterPreset p = item2; val.CreateFunction(p.Name, Soft, (Action)delegate { HolsterSlot selected = Selected; if (selected != null) { Presets.Apply(selected, p); RefreshEditor(); Notify(selected.DisplayName + " -> " + p.Name, warning: false); } }); } } _editor.CreateFunction("Place At Left Hand (3s)", Accent, (Action)delegate { StartHandPlacement(left: true); }); _editor.CreateFunction("Place At Right Hand (3s)", Accent, (Action)delegate { StartHandPlacement(left: false); }); _editor.CreateFunction("Mirror To Opposite Side", Accent, (Action)delegate { HolsterSlot selected = Selected; if (selected != null) { HolsterSlot holsterSlot = Mirroring.MirrorToOpposite(selected); RefreshEditor(); Notify((holsterSlot == selected) ? ("Mirrored " + selected.DisplayName + " in place") : ("Mirrored onto " + holsterSlot.DisplayName), warning: false); } }); _editor.CreateFunction("Toggle 3D Preview", Accent, (Action)delegate { SetPreview(!AvatarPreview.IsVisible); }); _editor.CreateFunction("Reset This Holster", Danger, (Action)delegate { HolsterSlot selected = Selected; if (selected != null) { HolsterApplier.ResetSlot(selected, resetGrabRadius: true); RefreshEditor(); Notify(selected.DisplayName + " reset to vanilla", warning: false); } }); ApplyStep(); } private static void BuildPreview() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_00ba: 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_0122: 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_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) _previewToggle = _preview.CreateBool("Show Preview", Good, false, (Action<bool>)delegate(bool v) { SetPreview(v); }); ((Element)_previewToggle).ElementTooltip = "Shows a small figure of your current avatar in front of you with every holster marked."; _preview.CreateFunction("Rotate Left 15", Soft, (Action)delegate { AvatarPreview.Rotate(-15f); }); _preview.CreateFunction("Rotate Right 15", Soft, (Action)delegate { AvatarPreview.Rotate(15f); }); _preview.CreateFunction("Tilt Up", Soft, (Action)delegate { AvatarPreview.Tilt(-15f); }); _preview.CreateFunction("Tilt Down", Soft, (Action)delegate { AvatarPreview.Tilt(15f); }); _preview.CreateFunction("View Front", Soft, (Action)delegate { AvatarPreview.SetView(0f); }); _preview.CreateFunction("View Back", Soft, (Action)delegate { AvatarPreview.SetView(180f); }); _preview.CreateFunction("View Left Side", Soft, (Action)delegate { AvatarPreview.SetView(90f); }); _preview.CreateFunction("View Right Side", Soft, (Action)delegate { AvatarPreview.SetView(-90f); }); _preview.CreateBool("Auto Spin", Soft, false, (Action<bool>)delegate(bool v) { AvatarPreview.AutoSpin = v; }); _preview.CreateFunction("Recenter In Front Of Me", Accent, (Action)delegate { AvatarPreview.Recenter(); }); ((Element)_preview.CreateFunction("Refresh Pose", Accent, (Action)delegate { if (AvatarPreview.IsVisible) { AvatarPreview.Rebuild(); } })).ElementTooltip = "Re-captures your avatar's current pose for the preview figure."; _previewSize = _preview.CreateFloat("Preview Size (m)", Soft, Settings.PreviewHeight.Value, 0.1f, 0.2f, 1.5f, (Action<float>)delegate(float v) { Settings.PreviewHeight.Value = v; Settings.Save(); if (AvatarPreview.IsVisible) { AvatarPreview.Rebuild(); } }); _preview.CreateBool("Live Gizmo On Real Holster", Soft, Settings.ShowLiveGizmo.Value, (Action<bool>)delegate(bool v) { Settings.ShowLiveGizmo.Value = v; Settings.Save(); }); ((Element)_preview.CreateFunction("Legend: Yellow=Editing Cyan=Moved", Muted, (Action)delegate { })).ElementTooltip = "Yellow = holster being edited, Cyan = moved, White = vanilla, Orange = ammo pouch. Red/green/blue sticks = holster X/Y/Z."; } private static void BuildLayouts() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) _layoutLabel = _layouts.CreateFunction("Active: -", Gold, (Action)delegate { }); _avatarLabel = _layouts.CreateFunction("Avatar: -", Muted, (Action)delegate { }); ((Element)_layouts.CreateString("Layout Name", Soft, _pendingName, (Action<string>)delegate(string v) { _pendingName = v; })).ElementTooltip = "Name used by Save As New and New Vanilla Layout."; _layouts.CreateFunction("Save", Good, (Action)delegate { LayoutManager.Save(); Notify("Saved '" + LayoutManager.Current.Name + "'", warning: false); }); _layouts.CreateFunction("Save As New (uses name)", Good, (Action)delegate { string text = LayoutManager.SaveAs(_pendingName); Notify("Saved as '" + text + "'", warning: false); }); _layouts.CreateFunction("New Vanilla Layout (uses name)", Soft, (Action)delegate { string text = LayoutManager.CreateNew(_pendingName); Notify("Created '" + text + "'", warning: false); }); _load = _layouts.CreatePage("Load Layout...", Accent, 0, true); _layouts.CreateFunction("Use As Default Layout", Soft, (Action)delegate { LayoutManager.SetCurrentAsDefault(); RefreshLayoutLabels(); Notify("'" + LayoutManager.Current.Name + "' is now the default", warning: false); }); ((Element)_layouts.CreateFunction("Bind Layout To This Avatar", Accent, (Action)delegate { if (string.IsNullOrEmpty(LayoutManager.CurrentAvatarBarcode)) { Notify("No avatar detected yet", warning: true); } else { LayoutManager.BindCurrentAvatar(); Notify("This avatar now uses '" + LayoutManager.Current.Name + "'", warning: false); } })).ElementTooltip = "Whenever you switch into this avatar, this layout loads automatically."; _layouts.CreateFunction("Unbind This Avatar", Soft, (Action)delegate { LayoutManager.UnbindCurrentAvatar(); Notify("Avatar unbound (uses the default layout)", warning: false); }); _layouts.CreateBool("Auto-Load Avatar Layouts", Soft, Settings.AutoLoadAvatarLayouts.Value, (Action<bool>)delegate(bool v) { Settings.AutoLoadAvatarLayouts.Value = v; Settings.Save(); }); _layouts.CreateBool("Auto-Save Edits", Soft, Settings.AutoSave.Value, (Action<bool>)delegate(bool v) { Settings.AutoSave.Value = v; Settings.Save(); }); _layouts.CreateFunction("Delete This Layout", Danger, (Action)delegate { string current = LayoutManager.Current.Name; Menu.DisplayDialog("Delete layout?", "Delete '" + current + "'? This can't be undone.", (Texture2D)null, (Action)delegate { LayoutManager.DeleteCurrent(); Notify("Deleted '" + current + "'", warning: false); }, (Action)null); }); _layouts.CreateFunction("Open Layouts Folder (desktop)", Muted, (Action)delegate { try { Application.OpenURL("file:///" + LayoutManager.LayoutDir.Replace('\\', '/')); } catch (Exception) { Notify(LayoutManager.LayoutDir, warning: false); } }); } private static void BuildSettings() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0132: 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_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_0202: 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_026a: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) _scaleWithAvatar = _settings.CreateBool("Scale Offsets With Avatar", Soft, true, (Action<bool>)delegate(bool v) { LayoutManager.Current.ScaleWithAvatar = v; HolsterApplier.NotifyAllEdited(); RefreshEditor(); }); ((Element)_scaleWithAvatar).ElementTooltip = "On: one layout fits tall and short avatars. Off: offsets are exact meters. Saved per layout."; _globalGrab = _settings.CreateFloat("Global Grab Radius (x)", Good, 1f, 0.1f, 0.1f, 5f, (Action<float>)delegate(float v) { LayoutManager.Current.GlobalGrabRadius = v; HolsterApplier.MarkGrabDirty(); LayoutManager.MarkEdited(); }); ((Element)_globalGrab).ElementTooltip = "Multiplies every holster's grab radius. Saved per layout."; ((Element)_settings.CreateBool("Re-seat Holstered Items", Soft, Settings.ReseatHolsteredItems.Value, (Action<bool>)delegate(bool v) { Settings.ReseatHolsteredItems.Value = v; Settings.Save(); })).ElementTooltip = "After moving a holster, snap the item it holds to the new spot. Skipped in Fusion lobbies."; _settings.CreateBool("Hand Placement Copies Rotation", Soft, Settings.CopyHandRotation.Value, (Action<bool>)delegate(bool v) { Settings.CopyHandRotation.Value = v; Settings.Save(); }); _settings.CreateFunction("Copy Left Side -> Right", Accent, (Action)delegate { int num = Mirroring.CopySide(-1); RefreshEditor(); Notify("Mirrored " + num + " holster(s) to the right", warning: false); }); _settings.CreateFunction("Copy Right Side -> Left", Accent, (Action)delegate { int num = Mirroring.CopySide(1); RefreshEditor(); Notify("Mirrored " + num + " holster(s) to the left", warning: false); }); _settings.CreateFunction("Flip Whole Layout (L <-> R)", Accent, (Action)delegate { Mirroring.FlipWholeLayout(); RefreshEditor(); Notify("Layout flipped", warning: false); }); _settings.CreateFunction("Reset All Positions", Danger, (Action)delegate { Confirm("Reset all positions?", "Every holster goes back to its vanilla spot (grab radius kept).", delegate { foreach (HolsterSlot slot in HolsterRegistry.Slots) { HolsterApplier.ResetSlot(slot, resetGrabRadius: false); } RefreshEditor(); Notify("All holsters reset", warning: false); }); }); _settings.CreateFunction("Reset All Grab Radii", Danger, (Action)delegate { LayoutManager.Current.GlobalGrabRadius = 1f; foreach (HolsterPlacement value in LayoutManager.Current.Holsters.Values) { if (value != null) { value.GrabRadius = 1f; } } HolsterApplier.NotifyAllEdited(); RefreshAll(); Notify("Grab radii reset", warning: false); }); _settings.CreateFunction("Reset Layout To Vanilla", Danger, (Action)delegate { Confirm("Reset whole layout?", "Clears every position and grab radius in '" + LayoutManager.Current.Name + "'.", delegate { LayoutManager.Current.Holsters.Clear(); LayoutManager.Current.GlobalGrabRadius = 1f; HolsterApplier.NotifyAllEdited(); RefreshAll(); Notify("Layout reset to vanilla", warning: false); }); }); ((Element)_settings.CreateFunction("Recalibrate (stand straight, 3s)", Soft, (Action)delegate { StartCountdown("Stand straight, arms relaxed", delegate { if (Core.Instance != null) { Core.Instance.ScheduleSetup(avatarChanged: false); } Notify("Recalibrated", warning: false); }); })).ElementTooltip = "Re-measures your avatar's body parts. Use if limb holsters look twisted."; _settings.CreateFunction("Rescan Holsters", Soft, (Action)delegate { HolsterRegistry.Clear(restore: true); if (Core.Instance != null) { Core.Instance.ScheduleSetup(avatarChanged: false); } }); _fusionLabel = _settings.CreateFunction("Fusion: -", Muted, (Action)delegate { RefreshStatus(); }); ((Element)_fusionLabel).ElementTooltip = "Holster placement is local. Others see your holstered items at default spots."; _settings.CreateFunction("Custom Holsters v1.0.0", Muted, (Action)delegate { }); } private static void SelectOffset(int delta) { _selectedIndex += delta; RefreshEditor(); } private static void Select(HolsterSlot slot) { int num = HolsterRegistry.Slots.IndexOf(slot); if (num >= 0) { _selectedIndex = num; } RefreshEditor(); } private static void SetPosition(int axis, float cm) { HolsterSlot selected = Selected; if (selected != null) { HolsterPlacement holsterPlacement = HolsterApplier.BeginEdit(selected); float num = cm / 100f; switch (axis) { case 0: holsterPlacement.Position.x = num; break; case 1: holsterPlacement.Position.y = num; break; default: holsterPlacement.Position.z = num; break; } HolsterApplier.NotifyEdited(selected); RefreshStateLabel(selected); } } private static void SetRotation(int axis, float degrees) { HolsterSlot selected = Selected; if (selected != null) { HolsterPlacement holsterPlacement = HolsterApplier.BeginEdit(selected); switch (axis) { case 0: holsterPlacement.Rotation.x = degrees; break; case 1: holsterPlacement.Rotation.y = degrees; break; default: holsterPlacement.Rotation.z = degrees; break; } HolsterApplier.NotifyEdited(selected); RefreshStateLabel(selected); } } private static void SetGrabRadius(float value) { HolsterSlot selected = Selected; if (selected != null) { LayoutManager.Current.GetOrCreate(selected.Id).GrabRadius = value; HolsterApplier.MarkGrabDirty(); LayoutManager.MarkEdited(); } } private static void CycleStep() { _step = (StepSize)((int)(_step + 1) % 3); ApplyStep(); } private static void ApplyStep() { float incrementValue = ((_step == StepSize.Fine) ? 0.5f : ((_step == StepSize.Normal) ? 1f : 5f)); float incrementValue2 = ((_step == StepSize.Fine) ? 1f : ((_step == StepSize.Normal) ? 5f : 15f)); _px.IncrementValue = incrementValue; _py.IncrementValue = incrementValue; _pz.IncrementValue = incrementValue; _rx.IncrementValue = incrementValue2; _ry.IncrementValue = incrementValue2; _rz.IncrementValue = incrementValue2; ((Element)_stepButton).ElementName = "Step: " + _step.ToString() + " (" + incrementValue + " cm / " + incrementValue2 + " deg)"; } private static void StartHandPlacement(bool left) { HolsterSlot selected = Selected; if (selected == null) { return; } string id = selected.Id; StartCountdown("Hold your " + (left ? "left" : "right") + " hand where " + selected.DisplayName + " should go", delegate { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) Hand val = (left ? Player.LeftHand : Player.RightHand); HolsterSlot holsterSlot = HolsterRegistry.Find(id); if (!((Object)(object)val == (Object)null) && holsterSlot != null) { Transform transform = ((Component)val).transform; Quaternion? worldRot = null; if (Settings.CopyHandRotation.Value) { worldRot = transform.rotation; } HolsterApplier.PlaceAt(holsterSlot, transform.position, worldRot); RefreshEditor(); Notify(holsterSlot.DisplayName + " placed", warning: false); } }); } private static void StartCountdown(string message, Action action) { _countdownMessage = message; _countdownAction = action; _countdownEnd = Time.realtimeSinceStartup + 3f; _countdownShown = 4; } private static void Confirm(string title, string message, Action action) { Menu.DisplayDialog(title, message, (Texture2D)null, action, (Action)null); } private static void SetPreview(bool visible) { AvatarPreview.SetVisible(visible); if (_previewToggle != null) { _previewToggle.Value = AvatarPreview.IsVisible; } RefreshEditor(); } public static void OnRigReady() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!_built) { return; } _choose.RemoveAll(); foreach (HolsterSlot slot in HolsterRegistry.Slots) { HolsterSlot s = slot; _choose.CreateFunction(s.DisplayName, (Color)(s.IsAmmoPouch ? new Color(1f, 0.6f, 0.3f, 1f) : Soft), (Action)delegate { Select(s); Menu.OpenPage(_editor); }); } RefreshAll(); } private static void RefreshAll() { if (_built) { RefreshEditor(); RefreshLayoutLabels(); RefreshStatus(); if (_scaleWithAvatar != null && LayoutManager.Current != null) { _scaleWithAvatar.Value = LayoutManager.Current.ScaleWithAvatar; } if (_globalGrab != null && LayoutManager.Current != null) { _globalGrab.Value = LayoutManager.Current.GlobalGrabRadius; } } } private static void RefreshEditor() { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (!_built) { return; } HolsterSlot selected = Selected; AvatarPreview.SelectedId = selected?.Id; if (selected == null || LayoutManager.Current == null || !AnchorResolver.IsCalibrated) { ((Element)_selected).ElementName = "Holster: (load a level)"; ((Element)_state).ElementName = "State: -"; ((Element)_anchorButton).ElementName = "Attach To: -"; return; } ((Element)_selected).ElementName = "Holster: " + selected.DisplayName + " (" + (_selectedIndex + 1) + "/" + HolsterRegistry.Slots.Count + ")"; HolsterPlacement holsterPlacement = LayoutManager.Current.Get(selected.Id); HolsterPlacement holsterPlacement2 = holsterPlacement; if (holsterPlacement == null || !holsterPlacement.Moved) { holsterPlacement2 = new HolsterPlacement(); HolsterApplier.CaptureFromWorld(holsterPlacement2, HolsterApplier.DefaultAnchorFor(selected), selected.VanillaWorldPosition, selected.VanillaWorldRotation); holsterPlacement2.GrabRadius = holsterPlacement?.GrabRadius ?? 1f; } ((Element)_anchorButton).ElementName = "Attach To: " + BodyAnchorUtil.Pretty(holsterPlacement2.Anchor) + " >"; _px.Value = Round(holsterPlacement2.Position.x * 100f); _py.Value = Round(holsterPlacement2.Position.y * 100f); _pz.Value = Round(holsterPlacement2.Position.z * 100f); _rx.Value = Round(holsterPlacement2.Rotation.x); _ry.Value = Round(holsterPlacement2.Rotation.y); _rz.Value = Round(holsterPlacement2.Rotation.z); _grab.Value = holsterPlacement2.GrabRadius; RefreshStateLabel(selected); } private static void RefreshStateLabel(HolsterSlot slot) { //IL_005f: 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) HolsterPlacement holsterPlacement = LayoutManager.Current.Get(slot.Id); bool flag = holsterPlacement?.Moved ?? false; ((Element)_state).ElementName = (flag ? ("State: Custom" + (slot.HasItem ? " (holding item)" : "")) : "State: Vanilla position"); ((Element)_state).ElementColor = (flag ? Accent : Muted); if (flag) { ((Element)_anchorButton).ElementName = "Attach To: " + BodyAnchorUtil.Pretty(holsterPlacement.Anchor) + " >"; } } private static void RefreshLayoutLabels() { if (_built && LayoutManager.Current != null) { string name = LayoutManager.Current.Name; bool flag = string.Equals(name, Settings.DefaultLayout.Value, StringComparison.OrdinalIgnoreCase); ((Element)_layoutLabel).ElementName = "Active: " + name + (flag ? " (default)" : ""); string currentAvatarBarcode = LayoutManager.CurrentAvatarBarcode; if (string.IsNullOrEmpty(currentAvatarBarcode)) { ((Element)_avatarLabel).ElementName = "Avatar: -"; return; } string binding = LayoutManager.GetBinding(currentAvatarBarcode); string s = (string.IsNullOrEmpty(LayoutManager.CurrentAvatarTitle) ? currentAvatarBarcode : LayoutManager.CurrentAvatarTitle); ((Element)_avatarLabel).ElementName = "Avatar: " + Trim(s, 22) + ((binding != null) ? (" -> " + binding) : " (unbound)"); } } private static void RebuildLoadList() { //IL_006a: 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) if (!_built) { return; } _load.RemoveAll(); foreach (string item in LayoutManager.ListLayouts()) { string n = item; bool flag = LayoutManager.Current != null && string.Equals(n, LayoutManager.Current.Name, StringComparison.OrdinalIgnoreCase); _load.CreateFunction(n, flag ? Gold : Soft, (Action)delegate { if (LayoutManager.Load(n)) { Notify("Loaded '" + n + "'", warning: false); RebuildLoadList(); } else { Notify("Couldn't load '" + n + "'", warning: true); } }); } } private static void RefreshStatus() { if (!_built) { return; } if (HolsterRegistry.Ready) { int num = 0; foreach (HolsterSlot slot in HolsterRegistry.Slots) { HolsterPlacement holsterPlacement = LayoutManager.Current.Get(slot.Id); if (holsterPlacement != null && holsterPlacement.Moved) { num++; } } ((Element)_status).ElementName = "Status: " + num + "/" + HolsterRegistry.Slots.Count + " moved | " + Trim(LayoutManager.Current.Name, 16); } else { ((Element)_status).ElementName = "Status: waiting for a level"; } ((Element)_fusionLabel).ElementName = FusionCompat.Status; } public static void Tick() { if (!_built) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (_countdownEnd > 0f) { int num = Mathf.CeilToInt(_countdownEnd - realtimeSinceStartup); if (num < _countdownShown && num > 0) { _countdownShown = num; Notify(_countdownMessage + "... " + num, warning: false, 0.9f); } if (realtimeSinceStartup >= _countdownEnd) { _countdownEnd = -1f; Action countdownAction = _countdownAction; _countdownAction = null; try { countdownAction?.Invoke(); } catch (Exception ex) { Core.Log.Error("Countdown action failed: " + ex); } } } if (realtimeSinceStartup >= _nextStatusRefresh) { _nextStatusRefresh = realtimeSinceStartup + 1.5f; RefreshStatus(); if (_previewToggle.Value != AvatarPreview.IsVisible) { _previewToggle.Value = AvatarPreview.IsVisible; } } } public static void Notify(string message, bool warning, float seconds = 2.5f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0041: Expected O, but got Unknown try { Notifier.Send(new Notification { Title = NotificationText.op_Implicit("Custom Holsters"), Message = NotificationText.op_Implicit(message), Type = (NotificationType)(warning ? 1 : 0), PopupLength = seconds, ShowTitleOnPopup = true }); } catch (Exception) { Core.Log.Msg(message); } } private static float Round(float v) { return Mathf.Round(v * 10f) / 10f; } private static string Trim(string s, int max) { if (string.IsNullOrEmpty(s) || s.Length <= max) { return s; } return s.Substring(0, max - 1) + "~"; } private static void TrySetLogo(Page page) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown try { Assembly assembly = typeof(HolsterMenu).Assembly; string text = null; string[] manifestResourceNames = assembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (text2.EndsWith("icon.png", StringComparison.OrdinalIgnoreCase)) { text = text2; } } if (text == null) { return; } byte[] array; using (Stream stream = assembly.GetManifestResourceStream(text)) { using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } Texture2D val = new Texture2D(2, 2); if (ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array))) { ((Object)val).hideFlags = (HideFlags)32; ((Object)val).name = "CustomHolsters_Icon"; page.Logo = val; } } catch (Exception ex) { Core.Log.Warning("Couldn't load menu icon: " + ex.Message); } } } } namespace CustomHolsters.Layouts { [Serializable] public class Vec3 { public float x; public float y; public float z; public Vec3() { } public Vec3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public Vec3(Vector3 v) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) x = v.x; y = v.y; z = v.z; } public Vector3 ToVector3() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(x, y, z); } public Vec3 Clone() { return new Vec3(x, y, z); } } [Serializable] public class HolsterPlacement { public bool Moved; public BodyAnchor Anchor; public Vec3 Position = new Vec3(); public Vec3 Rotation = new Vec3(); public float GrabRadius = 1f; public bool IsDefault { get { if (!Moved) { return Mathf.Approximately(GrabRadius, 1f); } return false; } } public HolsterPlacement Clone() { return new HolsterPlacement { Moved = Moved, Anchor = Anchor, Position = Position.Clone(), Rotation = Rotation.Clone(), GrabRadius = GrabRadius }; } } [Serializable] public class HolsterLayout { public const int CurrentFormat = 1; public int FormatVersion = 1; public string Name = "Default"; public string ModVersion = "1.0.0"; public bool ScaleWithAvatar = true; public float GlobalGrabRadius = 1f; public Dictionary<string, HolsterPlacement> Holsters = new Dictionary<string, HolsterPlacement>(); public HolsterPlacement Get(string id) { if (!Holsters.TryGetValue(id, out var value)) { return null; } return value; } public HolsterPlacement GetOrCreate(string id) { if (!Holsters.TryGetValue(id, out var value) || value == null) { value = new HolsterPlacement(); Holsters[id] = value; } return value; } public HolsterLayout Clone(string newName) { HolsterLayout holsterLayout = new HolsterLayout { Name = newName, ScaleWithAvatar = ScaleWithAvatar, GlobalGrabRadius = GlobalGrabRadius }; foreach (KeyValuePair<string, HolsterPlacement> holster in Holsters) { if (holster.Value != null) { holsterLayout.Holsters[holster.Key] = holster.Value.Clone(); } } return holsterLayout; } public void Prune() { List<string> list = new List<string>(); foreach (KeyValuePair<string, HolsterPlacement> holster in Holsters) { if (holster.Value == null || holster.Value.IsDefault) { list.Add(holster.Key); } } foreach (string item in list) { Holsters.Remove(item); } } public void Sanitize() { if (Holsters == null) { Holsters = new Dictionary<string, HolsterPlacement>(); } if (float.IsNaN(GlobalGrabRadius) || GlobalGrabRadius <= 0f) { GlobalGrabRadius = 1f; } GlobalGrabRadius = Mathf.Clamp(GlobalGrabRadius, 0.1f, 5f); foreach (HolsterPlacement value in Holsters.Values) { if (value != null) { if (value.Position == null) { value.Position = new Vec3(); } if (value.Rotation == null) { value.Rotation = new Vec3(); } if (float.IsNaN(value.GrabRadius) || value.GrabRadius <= 0f) { value.GrabRadius = 1f; } value.GrabRadius = Mathf.Clamp(value.GrabRadius, 0.1f, 5f); if (!Enum.IsDefined(typeof(BodyAnchor), value.Anchor)) { value.Anchor = BodyAnchor.Hips; } } } } } public static class LayoutManager { private static readonly JsonSerializerOptions JsonOptions = CreateJsonOptions(); private static Dictionary<string, string> _bindings = new Dictionary<string, string>(); private static float _saveAt = -1f; public static string RootDir { get; private set; } public static string LayoutDir { get; private set; } public static string BindingsPath { get; private set; } public static HolsterLayout Current { get; private set; } public static string CurrentAvatarBarcode { get; private set; } = ""; public static string CurrentAvatarTitle { get; private set; } = ""; public static bool HasPendingSave => _saveAt > 0f; public static int BindingCount => _bindings.Count; public static event Action LayoutSwitched; public static event Action LibraryChanged; private static JsonSerializerOptions CreateJsonOptions() { return new JsonSerializerOptions { IncludeFields = true, WriteIndented = true, ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true, Converters = { (JsonConverter)new JsonStringEnumConverter() } }; } public static void Init() { RootDir = Path.Combine(MelonEnvironment.UserDataDirectory, "CustomHolsters"); LayoutDir = Path.Combine(RootDir, "Layouts"); BindingsPath = Path.Combine(RootDir, "AvatarBindings.json"); Directory.CreateDirectory(LayoutDir); LoadBindings(); string text = Settings.DefaultLayout.Value; if (string.IsNullOrWhiteSpace(text)) { text = "Default"; } if (!Load(text, announce: false)) { Current = new HolsterLayout { Name = SanitizeName(text) }; Save(); } } public static List<string> ListLayouts() { if (!Directory.Exists(LayoutDir)) { return new List<string>(); } return Directory.GetFiles(LayoutDir, "*.json").Select(Path.GetFileNameWithoutExtension).OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase) .ToList(); } public static bool Exists(string name) { return File.Exists(PathFor(name)); } public static bool Load(string name, bool announce = true) { FlushPendingSave(); string path = PathFor(name); if (!File.Exists(path)) { return false; } try { HolsterLayout holsterLayout = JsonSerializer.Deserialize<HolsterLayout>(File.ReadAllText(path), JsonOptions); if (holsterLayout == null) { return false; } holsterLayout.Name = Path.GetFileNameWithoutExtension(path); holsterLayout.Sanitize(); Current = holsterLayout; if (announce) { Core.Log.Msg("Loaded layout '" + holsterLayout.Name + "'"); } HolsterApplier.OnLayoutReplaced(); if (LayoutManager.LayoutSwitched != null) { LayoutManager.LayoutSwitched(); } return true; } catch (Exception ex) { Core.Log.Error("Failed to load layout '" + name + "': " + ex.Message); return false; } } public static void Save() { _saveAt = -1f; if (Current == null) { return; } try { Current.Name = SanitizeName(Current.Name); Current.ModVersion = "1.0.0"; Current.FormatVersion = 1; Current.Prune(); Directory.CreateDirectory(LayoutDir); string text = PathFor(Current.Name); string text2 = text + ".tmp"; File.WriteAllText(text2, JsonSerializer.Serialize(Current, JsonOptions)); if (File.Exists(text)) { File.Delete(text); } File.Move(text2, text); if (LayoutManager.LibraryChanged != null) { LayoutManager.LibraryChanged(); } } catch (Exception ex) { Core.Log.Error("Failed to save layout: " + ex.Message); } } public static string SaveAs(string name) { FlushPendingSave(); name = UniqueName(SanitizeName(name)); Current = Current.Clone(name); Save(); if (LayoutManager.LayoutSwitched != null) { LayoutManager.LayoutSwitched(); } return name; } public static string CreateNew(string name) { FlushPendingSave(); name = UniqueName(SanitizeName(name)); Current = new HolsterLayout { Name = name }; Save(); HolsterApplier.OnLayoutReplaced(); if (LayoutManager.LayoutSwitched != null) { LayoutManager.LayoutSwitched(); } return name; } public static void DeleteCurrent() { _saveAt = -1f; string name = Current.Name; try { if (File.Exists(PathFor(name))) { File.Delete(PathFor(name)); } } catch (Exception ex) { Core.Log.Error("Failed to delete layout: " + ex.Message); return; } foreach (string item in (from kv in _bindings where kv.Value == name select kv.Key).ToList()) { _bindings.Remove(item); } SaveBindings(); string value = Settings.DefaultLayout.Value; if (value == name || !Load(value)) { List<string> list = ListLayouts(); if (list.Count == 0 || !Load(list[0])) { CreateNew("Default"); } Settings.DefaultLayout.Value = Current.Name; Settings.Save(); } if (LayoutManager.LibraryChanged != null) { LayoutManager.LibraryChanged(); } } public static void SetCurrentAsDefault() { Settings.DefaultLayout.Value = Current.Name; Settings.Save(); } public static void MarkEdited() { if (Settings.AutoSave.Value) { _saveAt = Time.realtimeSinceStartup + 1.5f; } } public static void Tick() { if (_saveAt > 0f && Time.realtimeSinceStartup >= _saveAt) { Save(); } } public static void FlushPendingSave() { if (_saveAt > 0f) { Save(); } } public static string GetBinding(string barcode) { if (!string.IsNullOrEmpty(barcode) && _bindings.TryGetValue(barcode, out var value)) { return value; } return null; } public static void BindCurrentAvatar() { if (!string.IsNullOrEmpty(CurrentAvatarBarcode)) { FlushPendingSave(); if (!Exists(Current.Name)) { Save(); } _bindings[CurrentAvatarBarcode] = Current.Name; SaveBindings(); if (LayoutManager.LibraryChanged != null) { LayoutManager.LibraryChanged(); } } } public static void UnbindCurrentAvatar() { if (!string.IsNullOrEmpty(CurrentAvatarBarcode)) { _bindings.Remove(CurrentAvatarBarcode); SaveBindings(); if (LayoutManager.LibraryChanged != null) { LayoutManager.LibraryChanged(); } } } public static void OnAvatarChanged(string barcode, string title) { CurrentAvatarBarcode = barcode ?? ""; CurrentAvatarTitle = title ?? ""; if (Settings.AutoLoadAvatarLayouts.Value) { string text = GetBinding(CurrentAvatarBarcode) ?? Settings.DefaultLayout.Value; if (!string.IsNullOrEmpty(text) && Current != null && !string.Equals(text, Current.Name, StringComparison.OrdinalIgnoreCase) && Exists(text)) { Load(text); } } } private static void LoadBindings() { _bindings = new Dictionary<string, string>(); try { if (File.Exists(BindingsPath)) { Dictionary<string, string> dictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(BindingsPath), JsonOptions); if (dictionary != null) { _bindings = dictionary; } } } catch (Exception ex) { Core.Log.Error("Failed to read avatar bindings: " + ex.Message); } } private static void SaveBindings() { try { Directory.CreateDirectory(RootDir); File.WriteAllText(BindingsPath, JsonSerializer.Serialize(_bindings, JsonOptions)); } catch (Exception ex) { Core.Log.Error("Failed to save avatar bindings: " + ex.Message); } } private static string PathFor(string name) { return Path.Combine(LayoutDir, SanitizeName(name) + ".json"); } public static string SanitizeName(string name) { if (string.IsNullOrWhiteSpace(name)) { return "Layout"; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); StringBuilder stringBuilder = new StringBuilder(); string text = name.Trim(); foreach (char c in text) { stringBuilder.Append((Array.IndexOf(invalidFileNameChars, c) >= 0) ? '_' : c); } string text2 = stringBuilder.ToString().Trim('.', ' '); if (text2.Length > 48) { text2 = text2.Substring(0, 48); } if (text2.Length != 0) { return text2; } return "Layout"; } public static string UniqueName(string name) { if (!Exists(name)) { return name; } for (int i = 2; i < 1000; i++) { string text = name + " " + i; if (!Exists(text)) { return text; } } return name + " " + DateTime.Now.Ticks; } } public static class Mirroring { public static HolsterPlacement Mirror(HolsterPlacement src) { //IL_004a: 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_0054: 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: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) HolsterPlacement holsterPlacement = src.Clone(); holsterPlacement.Anchor = BodyAnchorUtil.Mirror(src.Anchor); holsterPlacement.Position = new Vec3(0f - src.Position.x, src.Position.y, src.Position.z); Quaternion val = Quaternion.Euler(src.Rotation.ToVector3()); Quaternion val2 = default(Quaternion); ((Quaternion)(ref val2))..ctor(val.x, 0f - val.y, 0f - val.z, val.w); holsterPlacement.Rotation = new Vec3(HolsterApplier.NormalizeEuler(((Quaternion)(ref val2)).eulerAngles)); return holsterPlacement; } public static HolsterSlot MirrorToOpposite(HolsterSlot slot) { HolsterLayout current = LayoutManager.Current; HolsterSlot holsterSlot = HolsterRegistry.FindMirrorPartner(slot); HolsterPlacement holsterPlacement = current.Get(slot.Id); if (holsterSlot == null) { HolsterPlacement src = HolsterApplier.BeginEdit(slot); current.Holsters[slot.Id] = Mirror(src); HolsterApplier.NotifyEdited(slot); return slot; } if (holsterPlacement == null || !holsterPlacement.Moved) { HolsterPlacement orCreate = current.GetOrCreate(holsterSlot.Id); orCreate.Moved = false; orCreate.GrabRadius = holsterPlacement?.GrabRadius ?? 1f; } else { current.Holsters[holsterSlot.Id] = Mirror(holsterPlacement); } HolsterApplier.NotifyEdited(holsterSlot); return holsterSlot; } public static int CopySide(int fromSide) { int num = 0; foreach (HolsterSlot slot in HolsterRegistry.Slots) { if (HolsterRegistry.SideOf(slot.Id) == fromSide && HolsterRegistry.FindMirrorPartner(slot) != null) { MirrorToOpposite(slot); num++; } } return num; } public static void FlipWholeLayout() { HolsterLayout current = LayoutManager.Current; HolsterLayout holsterLayout = current.Clone(current.Name); foreach (HolsterSlot slot in HolsterRegistry.Slots) { HolsterSlot holsterSlot = HolsterRegistry.FindMirrorPartner(slot); string id = ((holsterSlot != null) ? holsterSlot.Id : slot.Id); HolsterPlacement holsterPlacement = holsterLayout.Get(id); if (holsterPlacement == null || !holsterPlacement.Moved) { HolsterPlacement holsterPlacement2 = current.Get(slot.Id); if (holsterPlacement2 != null) { holsterPlacement2.Moved = false; holsterPlacement2.GrabRadius = holsterPlacement?.GrabRadius ?? 1f; } } else { current.Holsters[slot.Id] = Mirror(holsterPlacement); } } HolsterApplier.NotifyAllEdited(); } } public sealed class HolsterPreset { public string Name; public string Group; public BodyAnchor Anchor; public Vector3 Position; public string OrientationFrom; public int Side; public HolsterPreset(string group, string name, BodyAnchor anchor, float x, float y, float z, string orientationFrom = null, int side = 0) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) Group = group; Name = name; Anchor = anchor; Position = new Vector3(x, y, z); OrientationFrom = orientationFrom; Side = side; } } public static class Presets { public static readonly List<HolsterPreset> All = new List<HolsterPreset> { new HolsterPreset("Hips", "Left Hip", BodyAnchor.Hips, -0.17f, -0.02f, 0f, "Side", -1), new HolsterPreset("Hips", "Right Hip", BodyAnchor.Hips, 0.17f, -0.02f, 0f, "Side", 1), new HolsterPreset("Hips", "Left Front Hip", BodyAnchor.Hips, -0.12f, -0.02f, 0.1f, "Side", -1), new HolsterPreset("Hips", "Right Front Hip", BodyAnchor.Hips, 0.12f, -0.02f, 0.1f, "Side", 1), new HolsterPreset("Hips", "Front Belt", BodyAnchor.Hips, 0f, 0.04f, 0.15f), new HolsterPreset("Hips", "Lower Back", BodyAnchor.Hips, 0f, 0.06f, -0.15f, "Back"), new HolsterPreset("Chest", "Chest Center", BodyAnchor.Chest, 0f, 0.02f, 0.15f), new HolsterPreset("Chest", "Chest Left", BodyAnchor.Chest, -0.09f, 0.02f, 0.14f), new HolsterPreset("Chest", "Chest Right", BodyAnchor.Chest, 0.09f, 0.02f, 0.14f), new HolsterPreset("Shoulders & Back", "Left Shoulder", BodyAnchor.UpperChest, -0.18f, 0.1f, 0f, "Back", -1), new HolsterPreset("Shoulders & Back", "Right Shoulder", BodyAnchor.UpperChest, 0.18f, 0.1f, 0f, "Back", 1), new HolsterPreset("Shoulders & Back", "Back Left", BodyAnchor.UpperChest, -0.12f, 0.04f, -0.15f, "Back", -1), new HolsterPreset("Shoulders & Back", "Back Right", BodyAnchor.UpperChest, 0.12f, 0.04f, -0.15f, "Back", 1), new HolsterPreset("Shoulders & Back", "Back Center", BodyAnchor.UpperChest, 0f, 0.02f, -0.16f, "Back"), new HolsterPreset("Legs", "Left Thigh (Outer)", BodyAnchor.LeftThigh, -0.09f, -0.18f, 0f, "Side", -1), new HolsterPreset("Legs", "Right Thigh (Outer)", BodyAnchor.RightThigh, 0.09f, -0.18f, 0f, "Side", 1), new HolsterPreset("Legs", "Left Thigh (Front)", BodyAnchor.LeftThigh, -0.01f, -0.18f, 0.08f, "Side", -1), new HolsterPreset("Legs", "Right Thigh (Front)", BodyAnchor.RightThigh, 0.01f, -0.18f, 0.08f, "Side", 1), new HolsterPreset("Legs", "Left Shin", BodyAnchor.LeftShin, -0.06f, -0.2f, 0f, "Side", -1), new HolsterPreset("Legs", "Right Shin", BodyAnchor.RightShin, 0.06f, -0.2f, 0f, "Side", 1), new HolsterPreset("Arms", "Left Forearm", BodyAnchor.LeftForearm, 0f, -0.12f, 0.05f), new HolsterPreset("Arms", "Right Forearm", BodyAnchor.RightForearm, 0f, -0.12f, 0.05f), new HolsterPreset("Arms", "Left Upper Arm", BodyAnchor.LeftUpperArm, -0.06f, -0.12f, 0f), new HolsterPreset("Arms", "Right Upper Arm", BodyAnchor.RightUpperArm, 0.06f, -0.12f, 0f), new HolsterPreset("Head & Face", "Top Of Head", BodyAnchor.Head, 0f, 0.2f, 0f), new HolsterPreset("Head & Face", "Left Side Of Head", BodyAnchor.Head, -0.14f, 0.06f, 0f), new HolsterPreset("Head & Face", "Right Side Of Head", BodyAnchor.Head, 0.14f, 0.06f, 0f), new HolsterPreset("Head & Face", "In Front Of Face", BodyAnchor.HeadView, 0f, -0.03f, 0.25f), new HolsterPreset("Head & Face", "Behind Head", BodyAnchor.Head, 0f, 0.05f, -0.25f, "Back"), new HolsterPreset("Floating", "Floating In Front", BodyAnchor.Chest, 0f, 0.05f, 0.45f), new HolsterPreset("Floating", "Floating Left", BodyAnchor.Chest, -0.45f, 0.05f, 0.15f), new HolsterPreset("Floating", "Floating Right", BodyAnchor.Chest, 0.45f, 0.05f, 0.15f), new HolsterPreset("Floating", "Floating Overhead", BodyAnchor.Head, 0f, 0.45f, 0f) }; public static IEnumerable<string> Groups() { List<string> seen = new List<string>(); foreach (HolsterPreset item in All) { if (!seen.Contains(item.Group)) { seen.Add(item.Group); yield return item.Group; } } } public static void Apply(HolsterSlot slot, HolsterPreset preset) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) HolsterApplier.GetCurrentWorldPose(slot, out var _, out var rotation); Quaternion val = rotation; HolsterSlot holsterSlot = FindReference(preset.OrientationFrom, preset.Side); if (holsterSlot != null) { val = holsterSlot.VanillaWorldRotation; } HolsterPlacement orCreate = LayoutManager.Current.GetOrCreate(slot.Id); if (AnchorResolver.TryGetFrame(preset.Anchor, out var _, out var rotation2)) { orCreate.Anchor = preset.Anchor; orCreate.Position = new Vec3(preset.Position); Quaternion val2 = Quaternion.Inverse(rotation2) * val; orCreate.Rotation = new Vec3(HolsterApplier.NormalizeEuler(((Quaternion)(ref val2)).eulerAngles)); orCreate.Moved = true; HolsterApplier.NotifyEdited(slot); } } private static HolsterSlot FindReference(string kind, int side) { if (string.IsNullOrEmpty(kind)) { return null; } HolsterSlot holsterSlot = null; foreach (HolsterSlot slot in HolsterRegistry.Slots) { if (!slot.IsAmmoPouch && slot.Id.IndexOf(kind, StringComparison.OrdinalIgnoreCase) >= 0) { if (HolsterRegistry.SideOf(slot.Id) == side) { return slot; } if (holsterSlot == null) { holsterSlot = slot; } } } if (side != 0) { return null; } return holsterSlot; } } } namespace CustomHolsters.Holsters { public static class AnchorResolver { private sealed class Binding { public Transform Bone; public Transform LimbEnd; public Quaternion Correction; public bool UseRawRotation; } public const float ReferenceHeight = 1.76f; private static readonly Binding[] _bindings = new Binding[Enum.GetValues(typeof(BodyAnchor)).Length]; private static Transform _root; private static float _scale = 1f; private static bool _humanoid; public static bool IsCalibrated { get; private set; } public static bool IsHumanoid => _humanoid; public static Transform Root => _root; public static float AvatarScale => _scale; public static void Clear() { for (int i = 0; i < _bindings.Length; i++) { _bindings[i] = null; } _root = null; _scale = 1f; _humanoid = false; IsCalibrated = false; } public static void Calibrate(RigManager rig) { //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_0462: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) Clear(); if ((Object)(object)rig == (Object)null) { return; } Avatar avatar = rig.avatar; PhysicsRig physicsRig = rig.physicsRig; _root = (((Object)(object)avatar != (Object)null) ? ((Component)avatar).