From 92bbd7233803a053d91a72851bf27d5db7cc8689 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 3 Oct 2023 20:26:30 -0500 Subject: [PATCH] [AvatarScaleMod] i forgotr --- AvatarScale/AvatarScaleMod.csproj | 12 +- .../AvatarScaling/AvatarScaleManager.cs | 37 +- .../AvatarScaling/Components/BaseScaler.cs | 5 +- .../AvatarScaling/Components/LocalScaler.cs | 7 +- AvatarScale/Input/DebugKeybinds.cs | 38 +- AvatarScale/Input/ScaleReconizer.cs | 6 +- AvatarScale/Integrations/BTKUI/BTKUIAddon.cs | 176 ++++--- .../Integrations/BTKUI/Page_AvatarScale.cs | 87 ---- AvatarScale/Main.cs | 8 +- AvatarScale/ModSettings.cs | 5 +- AvatarScale/Networking/ModNetwork.cs | 25 +- AvatarScale/Properties/AssemblyInfo.cs | 1 + .../resources/ASM_Icon_AvatarHeightConfig.png | Bin 0 -> 10232 bytes .../resources/ASM_Icon_AvatarHeightCopy.png | Bin 0 -> 15721 bytes AvatarScale/resources/menu.js | 429 ++++++++++++++---- AvatarScale/resources/nak_menu.css | 13 - 16 files changed, 544 insertions(+), 305 deletions(-) delete mode 100644 AvatarScale/Integrations/BTKUI/Page_AvatarScale.cs create mode 100644 AvatarScale/resources/ASM_Icon_AvatarHeightConfig.png create mode 100644 AvatarScale/resources/ASM_Icon_AvatarHeightCopy.png delete mode 100644 AvatarScale/resources/nak_menu.css diff --git a/AvatarScale/AvatarScaleMod.csproj b/AvatarScale/AvatarScaleMod.csproj index ce04547..712ea9c 100644 --- a/AvatarScale/AvatarScaleMod.csproj +++ b/AvatarScale/AvatarScaleMod.csproj @@ -20,7 +20,10 @@ - + + + + @@ -28,9 +31,10 @@ $(MsBuildThisFileDirectory)\..\.ManagedLibs\BTKUILib.dll False + + $(MsBuildThisFileDirectory)\..\.ManagedLibs\ActionMenu.dll + False + - - - \ No newline at end of file diff --git a/AvatarScale/AvatarScaling/AvatarScaleManager.cs b/AvatarScale/AvatarScaling/AvatarScaleManager.cs index e9835dd..aa39e3b 100644 --- a/AvatarScale/AvatarScaling/AvatarScaleManager.cs +++ b/AvatarScale/AvatarScaling/AvatarScaleManager.cs @@ -1,5 +1,7 @@ using ABI_RC.Core.IO; using ABI_RC.Core.Player; +using ABI_RC.Core.Player.AvatarTracking; +using ABI_RC.Core.UI; using ABI_RC.Systems.GameEventSystem; using NAK.AvatarScaleMod.Components; using NAK.AvatarScaleMod.Networking; @@ -25,7 +27,7 @@ public class AvatarScaleManager : MonoBehaviour set { if (value != _settingUniversalScaling && value == false) - SetHeight(-1f); + ResetHeight(); _settingUniversalScaling = value; } @@ -54,13 +56,11 @@ public class AvatarScaleManager : MonoBehaviour _settingUniversalScaling = ModSettings.EntryUseUniversalScaling.Value; CVRGameEventSystem.Instance.OnConnected.AddListener(OnInstanceConnected); - //SchedulerSystem.AddJob(new SchedulerSystem.Job(ForceHeightUpdate), 0f, 10f, -1); } private void OnDestroy() { CVRGameEventSystem.Instance.OnConnected.RemoveListener(OnInstanceConnected); - //SchedulerSystem.RemoveJob(new SchedulerSystem.Job(ForceHeightUpdate)); } #endregion @@ -121,18 +121,25 @@ public class AvatarScaleManager : MonoBehaviour public void ResetHeight() { - if (!_settingUniversalScaling) + if (_localAvatarScaler == null) return; + + if (!_localAvatarScaler.IsHeightAdjustedFromInitial()) + return; + + CohtmlHud.Instance.ViewDropTextImmediate("(Local) AvatarScaleMod", "Avatar Scale Reset!", + "Universal Scaling is now disabled."); - if (_localAvatarScaler != null) - _localAvatarScaler.ResetHeight(); - ModNetwork.SendNetworkHeight(-1f); + SetHeight(-1f); } public float GetHeight() { if (_localAvatarScaler == null) - return -1f; + return PlayerAvatarPoint.defaultAvatarHeight; + + if (!_localAvatarScaler.IsHeightAdjustedFromInitial()) + return PlayerSetup.Instance.GetAvatarHeight(); return _localAvatarScaler.GetHeight(); } @@ -161,10 +168,7 @@ public class AvatarScaleManager : MonoBehaviour public bool IsHeightAdjustedFromInitial() { - if (_localAvatarScaler == null) - return false; - - return _localAvatarScaler.IsHeightAdjustedFromInitial(); + return _localAvatarScaler != null && _localAvatarScaler.IsHeightAdjustedFromInitial(); } #endregion @@ -174,9 +178,14 @@ public class AvatarScaleManager : MonoBehaviour public float GetNetworkHeight(string playerId) { if (_networkedScalers.TryGetValue(playerId, out NetworkScaler scaler)) - return scaler.GetHeight(); + if (scaler.IsHeightAdjustedFromInitial()) return scaler.GetHeight(); - //doesn't have mod, get from player avatar directly + //doesn't have mod or has no custom height, get from player avatar directly + CVRPlayerEntity playerEntity = CVRPlayerManager.Instance.NetworkPlayers.Find((players) => players.Uuid == playerId); + if (playerEntity != null && playerEntity.PuppetMaster != null) + return playerEntity.PuppetMaster.GetAvatarHeight(); + + // player is invalid??? return -1f; } diff --git a/AvatarScale/AvatarScaling/Components/BaseScaler.cs b/AvatarScale/AvatarScaling/Components/BaseScaler.cs index 642a9a9..4f108ee 100644 --- a/AvatarScale/AvatarScaling/Components/BaseScaler.cs +++ b/AvatarScale/AvatarScaling/Components/BaseScaler.cs @@ -62,7 +62,8 @@ public class BaseScaler : MonoBehaviour public void SetTargetHeight(float height) { - if (Math.Abs(height - _targetHeight) < float.Epsilon) + if (_isHeightAdjustedFromInitial + && Math.Abs(height - _targetHeight) < float.Epsilon) return; if (height < float.Epsilon) @@ -70,7 +71,7 @@ public class BaseScaler : MonoBehaviour ResetHeight(); return; } - + if (!_isHeightAdjustedFromInitial) _legacyAnimationScale = Vector3.zero; diff --git a/AvatarScale/AvatarScaling/Components/LocalScaler.cs b/AvatarScale/AvatarScaling/Components/LocalScaler.cs index 68146e4..27ba198 100644 --- a/AvatarScale/AvatarScaling/Components/LocalScaler.cs +++ b/AvatarScale/AvatarScaling/Components/LocalScaler.cs @@ -1,4 +1,6 @@ using ABI_RC.Core.Player; +using ABI_RC.Core.UI; +using ABI.CCK.Components; using NAK.AvatarScaleMod.AvatarScaling; using UnityEngine; @@ -16,7 +18,7 @@ public class LocalScaler : BaseScaler _isAvatarInstantiated = false; _isHeightAdjustedFromInitial = false; } - + #endregion #region Overrides @@ -25,7 +27,7 @@ public class LocalScaler : BaseScaler { if (avatarObject == null) return; - + base.OnAvatarInstantiated(avatarObject, initialHeight, initialScale); await FindComponentsOfTypeAsync(scalableComponentTypes); @@ -83,6 +85,7 @@ public class LocalScaler : BaseScaler _legacyAnimationScale = _avatarTransform.localScale; AvatarScaleMod.Logger.Msg("AnimationClip-based avatar scaling detected. Disabling Universal Scaling."); + CohtmlHud.Instance.ViewDropTextImmediate("(Local) AvatarScaleMod", "Avatar Scale Changed!", "Universal Scaling is now disabled in favor of built-in avatar scaling."); AvatarScaleManager.Instance.ResetHeight(); // disable mod, user used a scale slider return true; } diff --git a/AvatarScale/Input/DebugKeybinds.cs b/AvatarScale/Input/DebugKeybinds.cs index 9756930..aa6835e 100644 --- a/AvatarScale/Input/DebugKeybinds.cs +++ b/AvatarScale/Input/DebugKeybinds.cs @@ -3,35 +3,41 @@ using UnityEngine; namespace NAK.AvatarScaleMod.InputHandling; -public static class DebugKeybinds +internal static class DebugKeybinds { - public static void DoDebugInput() + private const float Step = 0.1f; + + internal static void DoDebugInput() { if (AvatarScaleManager.Instance == null) return; - float currentHeight; - const float step = 0.1f; - if (Input.GetKeyDown(KeyCode.Equals) || Input.GetKeyDown(KeyCode.KeypadPlus)) { - currentHeight = AvatarScaleManager.Instance.GetHeight() + step; - AvatarScaleManager.Instance.SetHeight(currentHeight); - - AvatarScaleMod.Logger.Msg($"Setting height: {currentHeight}"); + AdjustHeight(Step); } else if (Input.GetKeyDown(KeyCode.Minus) || Input.GetKeyDown(KeyCode.KeypadMinus)) { - currentHeight = AvatarScaleManager.Instance.GetHeight() - step; - AvatarScaleManager.Instance.SetHeight(currentHeight); - - AvatarScaleMod.Logger.Msg($"Setting height: {currentHeight}"); + AdjustHeight(-Step); } else if (Input.GetKeyDown(KeyCode.Backspace)) { - AvatarScaleManager.Instance.ResetHeight(); - - AvatarScaleMod.Logger.Msg($"Resetting height."); + ResetHeight(); } } + + private static void AdjustHeight(float adjustment) + { + float currentHeight = AvatarScaleManager.Instance.GetHeight() + adjustment; + currentHeight = Mathf.Max(0f, currentHeight); + AvatarScaleManager.Instance.SetHeight(currentHeight); + + AvatarScaleMod.Logger.Msg($"[Debug] Setting height: {currentHeight}"); + } + + private static void ResetHeight() + { + AvatarScaleManager.Instance.ResetHeight(); + AvatarScaleMod.Logger.Msg("[Debug] Resetting height."); + } } \ No newline at end of file diff --git a/AvatarScale/Input/ScaleReconizer.cs b/AvatarScale/Input/ScaleReconizer.cs index 444659f..7bf74de 100644 --- a/AvatarScale/Input/ScaleReconizer.cs +++ b/AvatarScale/Input/ScaleReconizer.cs @@ -32,7 +32,8 @@ public static class ScaleReconizer secondGesture = CVRGestureStep.Gesture.Fist, startDistance = 1f, endDistance = 0.25f, - direction = CVRGestureStep.GestureDirection.MovingIn + direction = CVRGestureStep.GestureDirection.MovingIn, + needsToBeInView = true, }); gesture.onStart.AddListener(OnScaleStart); gesture.onStay.AddListener(OnScaleStay); @@ -50,7 +51,8 @@ public static class ScaleReconizer secondGesture = CVRGestureStep.Gesture.Fist, startDistance = 0.25f, endDistance = 1f, - direction = CVRGestureStep.GestureDirection.MovingOut + direction = CVRGestureStep.GestureDirection.MovingOut, + needsToBeInView = true, }); gesture.onStart.AddListener(OnScaleStart); gesture.onStay.AddListener(OnScaleStay); diff --git a/AvatarScale/Integrations/BTKUI/BTKUIAddon.cs b/AvatarScale/Integrations/BTKUI/BTKUIAddon.cs index c2a7ae5..6e276c4 100644 --- a/AvatarScale/Integrations/BTKUI/BTKUIAddon.cs +++ b/AvatarScale/Integrations/BTKUI/BTKUIAddon.cs @@ -1,71 +1,137 @@ -using System.Runtime.CompilerServices; +using System.IO; +using System.Reflection; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.IO; using BTKUILib; using BTKUILib.UIObjects; +using BTKUILib.UIObjects.Components; using MelonLoader; -using NAK.AvatarScaleMod.Integrations.BTKUI; +using NAK.AvatarScaleMod.AvatarScaling; using UnityEngine; -namespace NAK.AvatarScaleMod.Integrations; - -public static class BTKUIAddon +namespace NAK.AvatarScaleMod.Integrations { - #region Initialization - - [MethodImpl(MethodImplOptions.NoInlining)] - public static void Initialize() + public static class BtkUiAddon { - Page as_RootPage = new(ModSettings.SettingsCategory, ModSettings.SettingsCategory, true, "") - { - MenuTitle = ModSettings.SettingsCategory, - MenuSubtitle = "Avatar Scale Mod Settings" - }; + private static string _selectedPlayer; - QuickMenuAPI.OnMenuRegenerate += (_) => - { - SchedulerSystem.AddJob((InjectMenu), 1f, 1f, 1); - }; - } + #region Initialization - // private static void InjectMenu() - // { - // MelonLogger.Msg("Injecting into QM!"); - // CVR_MenuManager.Instance.quickMenu.View.ExecuteScript(Scripts.GetEmbeddedScript("menu.js")); - // } - - private static void InjectMenu() - { - MelonLogger.Msg("Injecting into QM!"); - string menuJsPath = Path.Combine(Application.streamingAssetsPath, "Cohtml", "UIResources", "AvatarScaleMod", "menu.js"); - string menuJsContent = ReadJSFile(menuJsPath); - CVR_MenuManager.Instance.quickMenu.View._view.ExecuteScript(menuJsContent); - } - - private static string ReadJSFile(string path) - { - if(File.Exists(path)) + public static void Initialize() { - return File.ReadAllText(path); + PrepareIcons(); + SetupRootPage(); + SetupPlayerSelectPage(); + RegisterEventHandlers(); } - MelonLogger.Warning($"File not found: {path}"); - return string.Empty; + private static void PrepareIcons() + { + QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightConfig", GetIconStream("ASM_Icon_AvatarHeightConfig.png")); + QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightCopy", GetIconStream("ASM_Icon_AvatarHeightCopy.png")); + } + + private static void SetupRootPage() + { + // we only need the page, as we inject our own elements into it aa + Page rootPage = new Page(ModSettings.ModName, ModSettings.SettingsCategory, true, "ASM_Icon_AvatarHeightConfig") + { + MenuTitle = ModSettings.SettingsCategory, + MenuSubtitle = "Universal Scaling Settings" + }; + } + + private static void SetupPlayerSelectPage() + { + // what other things would be worth adding here? + Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ModSettings.SettingsCategory, ModSettings.ModName); + Button button = category.AddButton("Copy Height", "ASM_Icon_AvatarHeightCopy", "Copy selected players Eye Height."); + button.OnPress += OnCopyPlayerHeight; + } + + private static void RegisterEventHandlers() + { + QuickMenuAPI.OnPlayerSelected += (_, id) => _selectedPlayer = id; + QuickMenuAPI.OnMenuRegenerate += _ => ScheduleMenuInjection(); + QuickMenuAPI.OnTabChange += OnTabChange; + } + + private static void ScheduleMenuInjection() + { + CVR_MenuManager.Instance.quickMenu.View.BindCall("asm-AvatarHeightUpdated", new Action(OnAvatarHeightUpdated)); + SchedulerSystem.AddJob(InjectMenu, 1f, 1f, 1); + } + + private static void InjectMenu() + { + AvatarScaleMod.Logger.Msg("Injecting into our BTKUI AvatarScaleMod page!"); + string menuJsPath = Path.Combine(Application.streamingAssetsPath, "Cohtml", "UIResources", "AvatarScaleMod", "menu.js"); + string menuJsContent = File.Exists(menuJsPath) ? File.ReadAllText(menuJsPath) : string.Empty; + + if (string.IsNullOrEmpty(menuJsContent)) + { + AvatarScaleMod.Logger.Msg("Injecting embedded menu.js included with mod!"); + CVR_MenuManager.Instance.quickMenu.View._view.ExecuteScript(Scripts.GetEmbeddedScript("menu.js")); + } + else + { + AvatarScaleMod.Logger.Msg($"Injecting development menu.js found in: {menuJsPath}"); + CVR_MenuManager.Instance.quickMenu.View._view.ExecuteScript(menuJsContent); + } + } + + #endregion + + private static void OnCopyPlayerHeight() + { + float networkHeight = AvatarScaleManager.Instance.GetNetworkHeight(_selectedPlayer); + if (networkHeight < 0) return; + AvatarScaleManager.Instance.SetHeight(networkHeight); + } + + private static void OnAvatarHeightUpdated(float height) + { + AvatarScaleManager.Instance.SetHeight(height); + } + + #region Private Methods + + private static DateTime lastTime = DateTime.Now; + private static void OnTabChange(string newTab, string previousTab) + { + if (newTab == "btkUI-AvatarScaleMod-MainPage") + { + TimeSpan timeDifference = DateTime.Now - lastTime; + if (timeDifference.TotalSeconds <= 0.5) + { + AvatarScaleManager.Instance.ResetHeight(); + return; + } + } + lastTime = DateTime.Now; + } + + private static Stream GetIconStream(string iconName) + { + Assembly assembly = Assembly.GetExecutingAssembly(); + string assemblyName = assembly.GetName().Name; + return assembly.GetManifestResourceStream($"{assemblyName}.resources.{iconName}"); + } + + #endregion + + #region Melon Pref Helpers + + internal static void AddMelonToggle(ref Category category, MelonPreferences_Entry entry) + { + category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; + } + + internal static void AddMelonSlider(ref Page page, MelonPreferences_Entry entry, float min, float max, int decimalPlaces = 2) + { + page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max, decimalPlaces).OnValueUpdated += f => entry.Value = f; + } + + #endregion } - - #endregion - - #region Melon Pref Helpers - - internal static void AddMelonToggle(ref Category category, MelonPreferences_Entry entry) - { - category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; - } - - internal static void AddMelonSlider(ref Page page, MelonPreferences_Entry entry, float min, float max, int decimalPlaces = 2) - { - page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max, decimalPlaces).OnValueUpdated += f => entry.Value = f; - } - - #endregion } \ No newline at end of file diff --git a/AvatarScale/Integrations/BTKUI/Page_AvatarScale.cs b/AvatarScale/Integrations/BTKUI/Page_AvatarScale.cs deleted file mode 100644 index 7e2750f..0000000 --- a/AvatarScale/Integrations/BTKUI/Page_AvatarScale.cs +++ /dev/null @@ -1,87 +0,0 @@ -using ABI_RC.Systems.Camera; -using BTKUILib; -using BTKUILib.UIObjects; -using MelonLoader; -using UnityEngine; - -namespace NAK.AvatarScaleMod.Integrations.BTKUI; - -public class PortableCameraCategory -{ - private static string categoryName = "Portable Camera"; - - internal static void AddCategory(Page parent) - { - QuickMenuAPI.OnTabChange += OnTabChange; - - // Create category and add elements to it - var category = parent.AddCategory(categoryName); - category.AddButton("Take Photo", "TakePhoto-Icon", "Quickly take a photo. This respects set timers & other related settings.").OnPress += TakePhoto; - category.AddButton("Cycle Delay", "CycleDelay-Icon", "Quickly cycle photo timers. Off, 3s, 5s, 10s.").OnPress += CycleCaptureDelay; - category.AddButton("Open Folder", "OpenFolder-Icon", "Quickly open the root of the ChilloutVR screenshots folder in Windows Explorer.").OnPress += OpenScreenshotsFolder; - - // Clone of the default camera settings page - var settingsPage = category.AddPage("Settings", "Settings-Icon", "Sub page of settings to configure the portable camera.", parent.MenuTitle); - settingsPage.AddCategory("Main Settings"); - settingsPage.AddSlider("Field of View", "Field of View of portable camera.", 40f, 10f, 120f); - settingsPage.AddSlider("Focal Length", "Focal Length of portable camera.", 50f, 24f, 200f); - settingsPage.AddSlider("Aperture", "Aperture of portable camera.", 1.8f, 1.2f, 8f); - } - - private static bool PortableCameraReady() - { - bool active = (bool)(PortableCamera.Instance?.IsActive()); - if (!active) CVRCamController.Instance?.Toggle(); - return active; - } - - private static void TakePhoto() - { - MelonLogger.Msg("Took photo!"); - if (PortableCameraReady()) - PortableCamera.Instance?.MakePhoto(); - } - - private static void CycleCaptureDelay() - { - if (PortableCameraReady()) - { - PortableCamera.Instance?.ChangeCameraCaptureDelay(); - QuickMenuAPI.ShowAlertToast("Delay set to " + PortableCamera.Instance.timerText.text, 1); - } - } - - //this was mistake, but now feature cause fuck it - private static void PauseCamera() - { - MelonLogger.Msg("Paused camera!"); - GameObject camera = PortableCamera.Instance.gameObject; - PortableCamera.Instance.gameObject.SetActive(!camera.activeSelf); - } - - private static void OpenScreenshotsFolder() - { - MelonLogger.Msg("Opened screenshots folder!"); - string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "ChilloutVR"); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - Application.OpenURL("file:///" + path); - } - - private static DateTime lastTime = DateTime.Now; - private static void OnTabChange(string newTab, string previousTab) - { - if (newTab == "btkUI-AvatarScaleMod-MainPage") - { - TimeSpan timeDifference = DateTime.Now - lastTime; - if (timeDifference.TotalSeconds <= 0.5) - { - // The new page and previous page are equal and were opened within 0.5 seconds of each other - CVRCamController.Instance?.Toggle(); - } - } - lastTime = DateTime.Now; - } -} \ No newline at end of file diff --git a/AvatarScale/Main.cs b/AvatarScale/Main.cs index f2d2661..b688c6e 100644 --- a/AvatarScale/Main.cs +++ b/AvatarScale/Main.cs @@ -11,15 +11,15 @@ public class AvatarScaleMod : MelonMod public override void OnInitializeMelon() { Logger = LoggerInstance; + + ModNetwork.Subscribe(); + ModSettings.Initialize(); ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches)); ApplyPatches(typeof(HarmonyPatches.PuppetMasterPatches)); ApplyPatches(typeof(HarmonyPatches.GesturePlaneTestPatches)); - InitializeIntegration("BTKUILib", Integrations.BTKUIAddon.Initialize); - - ModNetwork.Subscribe(); - ModSettings.Initialize(); + InitializeIntegration("BTKUILib", Integrations.BtkUiAddon.Initialize); } public override void OnUpdate() diff --git a/AvatarScale/ModSettings.cs b/AvatarScale/ModSettings.cs index 95a8623..f18cefd 100644 --- a/AvatarScale/ModSettings.cs +++ b/AvatarScale/ModSettings.cs @@ -9,10 +9,11 @@ namespace NAK.AvatarScaleMod; internal static class ModSettings { // Constants - internal const string SettingsCategory = nameof(AvatarScaleMod); + internal const string ModName = nameof(AvatarScaleMod); + internal const string SettingsCategory = "Avatar Scale Mod"; public static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(SettingsCategory); + MelonPreferences.CreateCategory(ModName); public static readonly MelonPreferences_Entry EntryUseUniversalScaling = Category.CreateEntry("use_universal_scaling", true, display_name: "Use Universal Scaling", description: "Enable or disable universal scaling."); diff --git a/AvatarScale/Networking/ModNetwork.cs b/AvatarScale/Networking/ModNetwork.cs index 1d129e4..a94147d 100644 --- a/AvatarScale/Networking/ModNetwork.cs +++ b/AvatarScale/Networking/ModNetwork.cs @@ -14,6 +14,8 @@ public static class ModNetwork { public static bool Debug_NetworkInbound = false; public static bool Debug_NetworkOutbound = false; + + private static bool _isSubscribedToModNetwork; #region Constants @@ -60,11 +62,15 @@ public static class ModNetwork internal static void Subscribe() { + _isSubscribedToModNetwork = true; ModNetworkManager.Subscribe(ModId, OnMessageReceived); } internal static void Update() { + if (!_isSubscribedToModNetwork) + return; + ProcessOutboundQueue(); ProcessInboundQueue(); } @@ -74,6 +80,9 @@ public static class ModNetwork if (!IsConnectedToGameNetwork()) return; + if (!Enum.IsDefined(typeof(MessageType), messageType)) + return; + if (!string.IsNullOrEmpty(playerId)) { // to specific user @@ -129,8 +138,7 @@ public static class ModNetwork public static void RequestHeightSync() { var myCurrentHeight = AvatarScaleManager.Instance.GetHeightForNetwork(); - if (myCurrentHeight > 0) - OutboundQueue["global"] = new QueuedMessage { Type = MessageType.RequestHeight, Height = myCurrentHeight }; + OutboundQueue["global"] = new QueuedMessage { Type = MessageType.RequestHeight, Height = myCurrentHeight }; } #endregion @@ -199,13 +207,12 @@ public static class ModNetwork case MessageType.RequestHeight: { var myNetworkHeight = AvatarScaleManager.Instance.GetHeightForNetwork(); - if (myNetworkHeight > 0) - OutboundQueue[message.Sender] = new QueuedMessage - { - Type = MessageType.SyncHeight, - Height = myNetworkHeight, - TargetPlayer = message.Sender - }; + OutboundQueue[message.Sender] = new QueuedMessage + { + Type = MessageType.SyncHeight, + Height = myNetworkHeight, + TargetPlayer = message.Sender + }; AvatarScaleManager.Instance.OnNetworkHeightUpdateReceived(message.Sender, message.Height); break; diff --git a/AvatarScale/Properties/AssemblyInfo.cs b/AvatarScale/Properties/AssemblyInfo.cs index ba2b41c..0227b18 100644 --- a/AvatarScale/Properties/AssemblyInfo.cs +++ b/AvatarScale/Properties/AssemblyInfo.cs @@ -20,6 +20,7 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonOptionalDependencies("Action Menu")] [assembly: MelonColor(255, 241, 200, 82)] [assembly: MelonAuthorColor(255, 114, 17, 25)] [assembly: HarmonyDontPatchAll] diff --git a/AvatarScale/resources/ASM_Icon_AvatarHeightConfig.png b/AvatarScale/resources/ASM_Icon_AvatarHeightConfig.png new file mode 100644 index 0000000000000000000000000000000000000000..08b68ea230a8fa87a61395952fe38cdd2fb7a029 GIT binary patch literal 10232 zcmd6Nc|6qL+xKVeyOL0e#MqY+S;`v87$TD0P_h?MUyQ+6vKBS=B|9xd_MHjkJ0YQx zWZ%h>hG_`T8Q<^k`Tg$SeZQXje*Sr0&%9nU^ZJ}~opY{p&UN0``?}62#^mxPc9!ET z5CpL!^>s}l2sT0eGBJRXppUJ|;1A|&dg%gG_MU$cJkYsl8)-vOMFQ(@M|$wg?5%I* z3qc$m)Gw^d>zNY-i9JN>YG3uYUm0ajvb!0y_9M|rH1Sx6t|0@OhG;?)%VKdTOkC<> zQJpTXFAPB@FNw~q5OiG^MhiK>=-D6~JvRb^cuWWoWU2LkS(qS9hkt5y#?Hsq zF@@OdK46mu)2CzM^X{_|Sxd?i4QQGq>*)(9RHezQ2h;kx*$l%-fRLGl- zp6$z!XoHDQ=nO5s3VvkI&zHX~<+s*`9kC5*p9H;%pker~g4}Q;iosp<^Todz1WOQ+ ztBIaNyijKp4Z~DH*KN7Sw!)O?LhY&89OP>9U1V^992Ct%&!+2@G82N-5L2~Bdwfst?nlhJouc7J9MWjf)sI8P)gjUP2$`uJ z_(`sm;?P4^2wL^B$yoC9ORzW)WB}0U7=Xv zr~n%*Ne4!oY$wrR-kxoDPeZD|I|)j9ZS_GbfEU>+jNF!i-}+!4UQVY2b>-ti2j);D zHgrp!g8NhQg$Ua9bMY|R8;fnc+uoRW zep95|j{B$GWO|_Hcp8Sc1DBYWD$o%+f>(cRIxyu%!(As_c@0{n(oNHZ3`4{lr1)rZ zaiPNTiN6hft~*A)I*DIcIsfziu?f|b+)&}Wi|HE=FUQRYh6_PkxKP|``l40e!~4hb z3(14QihMMCK+}ow@HHgqmt20G*~VpJ31}(-nob1NCV64!^!pEusIUr@Ma>|M}+g-2<)a(j6Fw(jM$3JDT+3N?)Pgh zMeL><^XzhDNiWYj3uu&VkGZRdh`5PC;x$4V$`Q0`+OR;;)b8Gthq4s&N}So>mz9=Q3oz6>%;wHfzB;#9lhH`uz}iO;yDwYq;I6`O-QAX#6kY#hEhSF2Xvf z5*rLv_nUs<>AXw`>qH!o-gRaz6aeDQ*K55k5{7A>UjkinzuNInIGE|;S)2Menn-1F zhhGt#e&oN$sqFHcEJLTuJi<`BWCdLY->%hKx&r$21=@grss{XzzOzPpbC+lz z^_L&f1Q-HXolC}Gsa^-ttaj2&jo7%K3iSJaf-76oBfBKvha+mRaG4O;}A3GiOiBc~}?L?_)sOZFOPB&1gW@QPHJml-Csw4OU7 z7cPXm0hA7q5V^<;uboZHiW^~~-lAt|EICkBaPNWe>SJ4> zNo#bj0Vr>hL-8O<5(ce<8#;*5U1j2bydzaf|AroQH zf6mzGqFPKsszeZaLx8vsAnD@+8U|6lgn*?RY~?9;msusqFA8;h9?w{8)8MvE2wEzn zKjNMOmtvU^SKRL>vX)Yc_YP-w2m{VYtu1+BY#mD++`eG&J9UPOSj3ghMIQlNUOQQs zxC6H^z+>^BIfyRsHN0A}9K^&4{G?8*Ynuec3*Rk*iF#J(eEIlj!fxAgPqfGAkq9^Xl$@tV#{Jov+MJ$s4BehJch; ztZp2|2!9N}SdhP;uCZt$$`=(FxYOWlZK{zo{Ehu3YzbfZnkC)8vzaZ_ zZ$rN{8WW$m(7SnLGCOcpwXC6`VXAk3XL~!cyk*O}rHTuBaA~c&*w0}n*{Mla@Oy>! z#*G+__#;P62+6(4SUr65LQBArm9fCJUc*eK-X4SHwY5H5--jBdjF9_)jFm8D9RGBa z{y_qKVc>ld)+S%MdOu&}$1E!(@0$4AnCKj{${unx?2ZZH#-gSg85z4jvF=9)Z3ZOh z`Z;Cevx?*`=sX5SLwitG4M6er~kM8JIdxaKVftk$Ia2I(79S zUJjZ4sQC(d{Um)B(J*;NM2bZL(n^xWd*T<&MeKjJ;5HrS$ohNWs6d^QcZuhSHmnN9 z6nnzH2*n9O2X(q;&md#QP_I!Myz86zH?I#t4xwWo7s?zK1ktR&?C|9bIuPz6Cb2-1 zB{KL&4Xy@z#CJy@(r+;5T8n4gu_WZ+ZTZ+>5Ql5>?;r#z%8S0VO)m8W3>Qe6`}veX zNAuS;f`xuFCLDH3s5&9#uY!>4wGc$Ml}Z<28|-^Z6I|s4oGzsD?4l16VW^qIVkuai z>(@#H)puu}KeBz5(B=W;{Q{~?7tLVH)2|@t_Ml7U{$+%rGMdG*T;2m<2-Nk&t@imG z3YOza?fZ$-!9!cGCk$HsIi)a?N|WtOtvH*0>jmX57Y_uzUoXN%_3%Iw8gd#{K@t<{ zfLnX#@a7CB_SD`M78Z7%sh);2hUJZOoIIDbxVoxTHSqQ8*E2FQ7z-6B`pFpkvdwEm z3s%CRX#81o;DiDs@}UW?$sV~lJBYNj=>;8^S%{2;J2q0T5|$4hLsI!UA{Xb(V4A0q zJs4HUf61}RNIfSWRw8IH29O$xR~6~EVQjNaE6OqsBrN?=MGw`_2gmTvmS9I{0eMZo z_Y}}n$btMaqe;8T8py6E$i7RolP>?rL1A@xB@Ls-%hAs%Dj1MgzIkqWull! z`B5;K&7Ss@9Yqq&YN;+kS$1H8UTJYM?wKP<34QdX=inh!z2&!Cbp;!9T{HuUWSVOs z!j$IDIGY?8j&{%7C#J9*@spdL|5v4M0y7zKUYz)XRa4`}FZr0U&37K$>xcJGtJ-W_ zb!32;25%GJ;BRtW#vSEe?+=z}(5lp}G)6;^;h(v>7RSaVtV-lgX~7bTy23z+BHcgT z(Ut;1?gd?bZL+FH`SZix(QAC%-fk^i>N?h5U-P=6+GKw0rO`u4dFK(^A5~?(4ddV7 zPjWp7rztaB6MT|rE1M3dr~`y+@%}A_-^J^Waj-$6T4dMFvEIhgQsu!9sMs;d{to}f zneV-350_?_Uy2ue5V^BAN38qi)7_}*JC}8{7{2nY;b#~6S39qUXR%uzT4fVyne*7z zWlo=Cm(X@GU(C?Q^-qCOiT^7!5J{3V1%$5;L=@g5vcwEP?-&6;YB?2fmapBh z&p_q#{f~LL$@ArF7c&nvU($yk0ObLO{yTd9&kIG^0!S}pV;FZe;<+pHUK(1*| z4lP8D^!|bM|8s5sA4rBFoo(tKKR&E*f$QHK=KmKfGNH%+U$acbX+8c`)Tf6kDKa*H z1RERo`6%2oK%>VMqBu@2y_@wp-;0U{mU)cDpN-{9&~wQNI4Y%dxGiMA$ayI%B_-vk zot>R>y2R;DE=6eKUT<&je45Z{z5kGK=oHE9eZRQ4NC{H7hyRTg?9UlAJS+sP@cO{O zK&31AyhuNX3~triRqf?IoR5Q@5=E-MjyX~>1%lFl$!1K5)6&w4d7r*U0{cn0f(Z=l zo7OE|xI%yq(fTqEym4MqyWANI7%L=?NIhjFZw7b)PUY357{C}o7KAX(q~0;j)HQJ@ zVzp%PP6VdZJT>sCVfujly`_(94I2+^h6Hu|OW(eIJDHc4XXd%ra&)|VYDwF}W4Tw# zq73_DU9cDmBtWJ*ny-rPrlKZ;7n3dQ1HyT-Qj`ys2#B$mkSyv z?GBQ!433Tl`DKh!b6t7*nLk#fuulH0gDvFSBfMU!&C_G0s3AbdBVi)=A z3Z+*!mv-{d@jcx~i}HX#Uv*s_S~jx;#G|SNtIZUz$H6$?uxkO<(O0sg&9R)DK_AE+ z&9*g#sfbje*M7Eyb@Mco@Dm%n_uvR!DG-zk8==`uHAj|O)9cZYw!B}p(KQhc86aU{mQGLovoXzZTow?%D2AWtqdR@m%u+A z`T8~GT43=@p4wH_%h_s_cPiatEE`Qj*p&Jdv~6HZ(L&$K#&G`u`kgoE_Up|!n_lBF zlwt9`q&T|TAA`Z9ELWI~hAYWE4GU&=b9eu016JUToIrSZxRm5*za)ojDgqok3a@jm zCl6g!rP7~m`XHd~6?b54uxu@GJN$6$gltN@>?eaC*%>7DF?a56f08gwuf3P}&{ibz z6IU@#z2hgYD;IZi8bdXo?Ia1a&u0}Cdyvy(w`)ji+OfX^hDSyzUp>l$zI>7slubd1 zIl{d4Oy60!_4BLwuUBEBq|n_Ki{s&YCl|)=m&}%sTzpqLrCIoJNAOo$^+kuMX6JBn zHm<(@U^z>~(Ve}?U|^V~4yB!kms&kAnThArA3K#U(Lb-MDSU@#mUYAv%#2NBd>%wD zN=ObQhkmO}K--K^jITJlzTFwvfmWqkf3PZFyu3)m<;tfBU%FY=p)Zn-EPVR4=X-0D zEZ}51ogEWG_tEInxP2d}NS_FRubpP~YxtUfh6 z4j@!T=2?$xb4w-V&JxEz4_jhn0kT=XHdXYjsv+5eNcUA_k?R*HkHrR%D|BE-^}l*E zH{g4io{bOhphBLMHbR;XTJV5f+|0!UYf1VUy?DX#6t|c z2Ri=;43M;oO=+2+b!Pe4`Kf3={~!L1hU>Y_87V$d(@ZBcLVA&fSQqBF;W^$KwEM!m zWNct$WQXG?mr3&fb`8&cL56gqdeB&N7x(>*?f8ce-d~#OuFh=yrAh#XruXA>vo@z< zEvvG>=FFwN<=i?lFtCy1%#t*-WYq_fmN1d9q_vBt?Q8O84z}BHqqfrY=YwF8-*-D# z`HC86V=K~W;ESn>yOqwxmkV$(6=Mw(-p#G8Y!}e)fmg~q5J$aZl>CN3AiTrMGSZ$` z)pLANXt2Hgk0Yi@pdK+$ct;LE!`BnH>nHuUa984Zy2@eKK=S6FDLYj{*%@zl+3xiv$qdR&Eo${nPk(V!DhJPz`lHMICp65t=o(NR+&KmpVHrJD$5FamF z!NJLygB`N-JG*#ozF^;XcP(wdvCdZ04|n6g$_D*f7e5{kJMY;Qe=>cxJJqGop+{=( z1I;Y}8zVzQ6`z~VEpC*o!gx@w4h|Dn$5)@;T8+NfQldPYi&NKuC1}IWUk96% z{_upd^Vav_8}<@exa5Gz`@B6poYu`zoPxp4*#j~z!<9GZ$t05WkU~Vzx#BXoG}PQ-aaGLmG|BEF`USnB{Yir61`>t0OWVj1tqo%Td%n%dHNw*T}pH)=+ zsQLW)b60OQK~LU{kex@xAz{-Ot^h%kj`8y=Dkv%{KIlo4pFVHOq}7!M#FS39?0%5QT;fTo#r=u5b(pPRIeP_2YeivZ*j>4=EG^+b9oo0)TUX6j? zmR4P2siI3jp~`TM5K5bVYos>)nET`a^95(GU$+hFH89`ojnfnc4Qon{*+$akx?8s{ z50!_gCwT?gN}`K2qxRIcebZA-XzkvPQ)$hc1>)^FP02XG9rzlqwO&l}{tY%SI;LdS zMwhwkpt#C?ce=o)T`=6pt(_b47F&40=nF+2rp2ex6%7!-^|b}7TG z@gUm?9Y$`9c^wXX-Jb{O(P>PMgMwjo^>2YP>LU$O?Pmk``{=&}KV<$CTj`lMC6W1d zU%?_kP6o&H$}`RYXv<`kk&+Yl>%w6TFvx|J;@SDr@w8D1fKgxVyfd+Wz>@y+T~W51 zmsgvul7)FJ#TUXw8y+Nv)*rEnSl2mSLl_n+5nCNB2ae*s=sRK>rsL0_0n4kbkaWg( zuIG|PxqVQ2dhuI49QFD8c-y|I!bRp!t^42q1Fwtl1Qr|NsdT=}&`didCp$ZP-?5m9 zdWj{pyt1NRUQ~4Rae8sso`#N&4!d*gArr7{p>uO{zCDPe16w=w)bvkMQFmWs>Fr`B zX6j-+YCm_6YRQ>y`HLG>vL%@k7urE!L7erex>XzLAQu43XWXkh;SHn9sU= zPofI1%9j{rDlLxXq-!@^ZBO#Lc|>O92S{fh9QPY0FS3HpILo-ooRpop$UUTmkOuzIoH05bL0G+OfBp$k3=zLa-VC|4PyS=&Yt5B? za*zaC{q3qdMRE&}FM)Nw@38Z?ceYlREnZr0@}LvU;x%?^Gj0w}Rg6;2_ikB&F6riT zie;H*!avaLdu!CqwU>_>+Zm6aIDz)Kbt~wbVb{XqVuL>jlVZ~`My=7M3rkClM8hW? zAmW-|%+5K6G43{RdyvF3d*VYft(^?QObnPz)>Fa4?NIk(t&5GGYfBa5RGRRU6n>Xv z7mf2FdHSd)elvUm_>ex`uGS~cYYOxR1E>biF}qT0fMKW3;w#A|z?$C=qCEWdWCkK> z7$($O%03NwSY0`>i!Vlh7RAses(_Q2RSW2`@**v55BD?uw$jDvqjqwDso|IK)fJ#W~l%KxQTk+JT^tTr1{PFdCht$5EzRWP2|%9je^s+-+B3bgL?+drtz z)VF7#YIQfm0=K>J!@(joA4D+k`-@xz1v(S_>l?X^Kzg^OW!Goe)?8w)4_0ww@tC6m zs^72aTDw~Oq1Nd;5gh$R^XJ!^6I;-_7X%lCZf4z^6=Da#uY!K-5Yf(u5jf1 zqCmm!9UfLQq3Zn@C?E?QqOIc%i3~t6&!=Qh;wL93iAu6Yfb?|6R%K6~K5?LHg(DD+ z+Zhl6k))?3CUSYISuqAQ$)q0U!xN%*v8#)VR=0~E=i?@u?5pT;VXdvLEMc;^ z@M(sBQeCp)lXIKzb)q=#rMne^d!$u()kU_s_fImdn*HVBY+`N{4i1hn{vp~O2~auj z9G7O&?tSIkEU<`Qt6k2Sx){MPp$?YU+J?`Cb48*&lgg=MvV#g6csX51rIJBpSl)SY z$9lpwiX^ym8oWV3+C>I`^ORbA?8v7k5tQmv%l9*9z6FJ9;M2ctJ!8na1e9GR)O5A|1DV`&&@jPX`Tic%c!gy2w z5m}Z@RZmz$E#eP>E?s{f9amJ+R=2meP0kGwENex}rj%zKyuxv38^sylKRnz}1Z>(?K}I5{&ue92 zA^^9XBvrU>ENcN2fA{Cxzw)zOG#K&MO;V2_GEQS6X!{J5GA8ev7nVAj# z+>XdKeRJOWhu_fr(%0ZVTUoF_fFqX0W=EC?R#ven?2yovnn~CK1Z&h@Q+fArj%3fb zTvR=;!P{@=2A!FgD~u?o+A1N&?p>UZWy`bNqI; z#-{~)vOEuTJj+m=4E@YA9MxoDOrP_`J7MXTD|T(k$93swKS8jWH>L9wDF{VakJ41 z`7xD!aWF|kqJKH}7QgXVX^I`vyzgdwK}5%wWurKdQp!UJToxP}^TxjecCQs+eF)QI zOOBr2$ib5hrW!BR@T{GQk!?yHWn~{8f@6Bf%J;33^Cc(6$r!OlUN;oTL48GZOTTNG zEIcs4cX!te=B27&CpgLZh97)!%{?3bf5s>|Z&oR~e zV_-`ouS8&C8Ty7mocLB`q9yexyeJUN#zkg>!IexN;t6;!*DkMas(lT%I$}^ar0p19S)WAy zcuAmDx?&^nnr{`y=yEdW_KQ{LqqTo$LEG$?vzRbF7+2Q?zbV;z_pvTTs)4}@^`3Kj zjh5g!R~pxxk46?A^=|Pau;?^2xfT^+kD@+6rZ<{rUE?=J6Iv6dPoB7JM#V|37Y{VD z7X~WE3hh}v2P@WYX1ueYCe7tPM4eGoQra8(@ZnKOLa177FWeRViV>taKd9Ha4Hh?S z;5b#Nxz03z>*i~6*-X;um#D0s|Dv%i>$DJ?_+Jk>=$>QK{eWfu%Z=&v_822R@B$Jp zO=Px#fV~n8t_~o1WP1%^gWfSsA$J<2V6`6Dw(->0)NC@p$Hi0Y|NY%E`>tajeo!M3 zJy~9U7p<tXxVdU8t0oJ9l)SrfYC!<*iJm_;bcaC5nlJzG+FY`& zAP|XjWd&KCm!=z&M1CgLNf+CUPvY+imzBvz${2DJC~AF#e_p-Kovy<~75;NnS(XWT zl=nM3SXYrIp13otN=B=Njon_xnmdn}4dvgLbDb+wGorj7&Y;rIX}5dfzva!F!GWtj zOkNOM@|!9e@!E9f6-Q0%ophd{Jt z@UB5_6a4?b?42=nc*xH`gOIUjfcYY9NPbG8;t`xRBQ&a*1+n;ORD)c@HkJ?&q>yV0;b^wdJKQ~M~2tV}^{wPFHX1y~z8;IS#;DfX>+?LWsk z;#^VpQ5pFa#@5wMZbeg##X{q$JxVD9U!V+0kDK&x{-}$R(?+=midI~WT)C6bdx*U^ zQYJ1L>lTs3+g>p4&goMJKPEe_1et{oW6? z^?^y3ezi3GCPMspnsuw}tA&_?%ge_-yAAf$Ev3pXkRdcAo$H`-`381!=N5KWY`;Qi z{Rob;^ht;8F&$pT`9(?(PK&#%SJ@`(8QYy2pQM?ZE*ahnTyjsu+&?+}GNW(#dGG^CX&HXTjv zEy%+1<>`fv9cq4jV*VXu>4E^R_NV?4I-x2HQS(!O?0_bcGg%D=-oc=}X(Z(!q15_# zHus&B|>?jT3?S zJj^F$_p3~S$9>%S^Q4|(98YcS^DC`-e5PbP_BA0~^?*R0pY9Xsa^z7=&zjagQiig9 z{HK0vI)}VNw@WA3(O>MY6KbEPJ=~?CgjWW%jumv)^_f4#nR@dxdi35^9Je zWltp85qy4aXdY6WVMCpqO|LnyE#24(VkR8niE6j%)-QCVW)G)Ov&a=sC)lnZr( z+1}f-SAnFA^D~EXHW2|`xp*(ylwmHtOYDF+QFuVmrzJAwfxR4_Vu432`CO)L;{}tD z13InmAT^v0JJh70pc9QBg+MYklV4S9SvP~0tN#%HAs~iiQ#@u_*t(Ldh^Gkikg2u_ zWD6L8`NSCAaC#qP#m^R!3kDeJRi%IT_r_*914Cx-ipt|3c`y?BbZ#p1!62u5ak{u3 zBkW@QHMP4TNk25HiTQKOG4Ok=cf`2A!DI!6oMU5wV$%hyfT|z;Eyi%QxzBMi0X&G1 z-J#o2x_mG^U8{dLFA+Z^+)kLmp-y^THFx=BmVw_Y=!t_cgbDlKQI1uQ>G;teRaA{ zftc*sy>{)I@eQff_4UCtqVZ~#=2(9p7b;7rh9Qf+i;I~_z!E`9*;iJf4?*NcyrhZj z$8qquiuZK|G#kxbw3abKLM?*(Z&;ppOCF3`N^fj#o_{#QH*t>FkD)nR+DjRE)l*p6 zHtAo3m|R2t{o0?tHE3T+3YWbc>E`MH^}$ll(nsEa^XqT$qwF0$iXOLNHa&$bF5JVC zLsM&mIr#-HXF%&)({z4Xt)=oV-~cEMVgkCMR7h4NOYud`1P?#=WtDi`fpEUKe?htf6rci;VIg(r`ezzR#+ z6Z!7S|Mvoyv$z&L))SWYijeX7JH~#wmixt*yK}#h2bvF8BNWNL4g}ABa?|uf{&dv{ zzmSf1$0elh*xB>W->ztX}%`&TeY>)zjgoTar3p zy%5=iomO#H$l;?iS&aR~Z&Qi}o(Z0t44|RjyHMttcYlX=TMIu#2+LAF=tnk_2XWqH z0nchCuxwH_eK}dQzif}RdKIDqEDV{2UjG4I4aw7}?aBHH9pz4SozYh7x4iwLH5h^) z<#QVE3zz72FWT?jwM4bG*j6vJ0mVTE6i3x~(^Td5%SLos7nffjmd$4gu}4Ce4F<74 z`s~Q9SD~f5g5+vfjoqO@#kZ(rJ$(Mts6?>)MO#M6*Av6qwQ)T`HdZuM`U*>axW!Z= zop+!+yKfs=L7Z$muBtlN=?Djy$Tc+unI%E9TR->zUK0L@uGgh^q_Lx zUaN$ui!L&B_)=txZ0z2=a1a+qqR9{%K61TL6Fji-Hecf-;{BI-aQPFiz<(haS7X>u zkI4Fow)i5=NL$#6;oL;OCS|DMW^ot9-a9?Q)>Y27+ zPW#j=yi)W+uaA4LD1KysiBl|Y;qdVICGzuyqSw^2kkJ~7?wqGCja{3r`4z1BeEih+8;X| z+|gLziBjBUBrD(hSft6d7x;lAk)msN=J}#gEN?yf(Gs~K3y+z_U4}lfZnq z$CJk~3oSd;q3AnZ-m-$izLyxFn!)r5{LqQ!EJ{-oDlbQ4r?xFjGfdd4dw`XT=MasC=K%a;I!g0eh+irpOq%y7nDw+&$>{ zsZAmQJvh{e09&zkH|ryAv%!J03izXYl4ubDl?#^Rppp6fd;5yr$o3;F>K(#Q!oVz# zR?4>Te6`15v&?Sf? zi`c6@bik!ReNMlpF(#uS&4eNbrq+G&U7XktvOR`_jNS!sNmN}2u3=g`(&z1X+J+r= z7Owys&;U1zJ?}#|5FVds@+I}1!6Fqc_C)cL(;&^X+;z5wg9H77Pg5S|(1rU{PZwv4 ze2Qn8d(18Aw-KEmu4e8trKW0iXCIn|j9m49@l zK3C(PXqy@P(I;M8iA=xO_zQ<0u8n;;&^`}?*S@8G6Z-tsGpz>$^C^#@_5Gy5-G7Ei zV-GkreB}~CgUcx*U&udoIedzGsCsJPIGw3%EkMi*=zsEj|{)QZ&on%6$I3&$}88pN-=j^@kOh1s1RHW$t zd^eNv*R;VX!|)X<^S_%#s9o4Go9?@{Je0IiY{ppT@y?)o_0JSprNLPOgmm7WsT`X9 zva$qtY|rixW~hZdIvIK4en#)%{(jMd*6!eilE9c-I=pB10~;}aX-5Ca;P+b$iUZ$R z^o`1FgjKkYS2K|hb9_iv-#FmM+GIYn^07*t%HlkGQd-x#Ll7C7lg@OmYcZr4K*v#G>vH)fyeR_U+bVVNapr z*X6u(;FOwWd&+%+#_(1n#-QxCXlq6vwVJmkREZmTJ+?nm_5GcX9X+U?Enu|UWKy~? zGzG78jZU7fVfvy>{naC;4&V6Hwjn$Q7A?Os$8cuY?dVU580Fl^x|7C9z}+arAS8#j zaM{o-$4s@S_8{u1gdR|-%i}|&vn%t0k6&46X&A>{#UT6^NFrGR1+wDzYi zUZT-7k~qc7!kaI{;cxT^^f3iPzx)$2xonK~1ZCvFg9vp83th+Z*@)0Y;d$d0xjkas zYgtO=RLB)B^mnWYwJE6x=03bQl%6OJ6y0*_Ep0@1=|zAZ$$S;=h2fLj-nw@9qWsHn z77XrFVMMy285*J)h&TTUHPrj7fQ-@Y?qwZ~%R0{SQ_h}=Fv}p$IYqo{?+I5o?4>P} zDpg%7rMR0OLkQ?(^qi)DCAst&HfATqc<-%z%rQ=fTxn1ISu@!N+k26oiTPLwkZUw( z@W!6;jwI>}ln08ato=gJhgdTG0O`KcUESTSPTH~IqE(cpu@x<6=HU}_py}&-vbys~ z#;5Gj03j^PkgIC@Bz&PNHJq4io=}sDK|KHieBsr7fx53uq#G%;LRzw5c(%v9;)6S; zkug8M*vsz36rTb^8H67tw1FHOL8m!7Er@jV+xMNQL=t4{et{Fj?`N&_v)?1#J&Z5< zBLUn>fw3J$oU{R1@w#oA2>$%EJ~ZWeB3%@IR8_V}-jWk{6+?i}r#EBUG9}BA#v&8s zsG?$0Vt#Z+lCzEBd8^w;>wE$kS3AMDLjpC&OIsgZS%*V6SSi&yKzaquqWxAfxJZEi zj9BrAt475^ed=#Og3l@!;$$i1fzN;_D)IZ4m9>O5F)?{G>X2>5=AW#lrj|K8JiNmb zXzbhQR%PveL@bYnutQNCvP<3bWBv0PC%Ah)eXK_JRnroSnVdJ2p7 zxdI6-=>VQ>><+cIJYM%hwOoW_b&~+x1=4ukqxa_*s5GD19bKxK^?nSaT52!G6hhZk zfC`2kqKe*&6F+~rLSJ+)uwhz{A2?f3dHQ7mMiWD~f1NNUz|v2s3)=)6F&sM0 z*6KQN2ntZ|2-F~41;t3cT`80cqO9baKp6gd10|F)m@^RH$XTpaJ7MU_Y?ml;@r6yT zKBP6{Y|@jxkY%e9D&9aVCWCkIYYNpI#2FY=J&9KHA}c#>1jG_k8stO`Yo;!YA0hw6 z+Ss8l`tS*^2m19W@hO%0tDHZpAK4*CBMyCO+(o6xSBJIGb}{1O2C_=zbq1LLr!v1T zbi>-kGw;!$pj607WQV>?fbPSd-q+j+n`}#bEq*F<>FDx05hQ;5hc+0ZInO__-22)u zI1L@asD{tAjOGKp`QYx&fRu$#GzGI8B?_|Bvo(en$qwxDe;ZFTY-J&(MWr8?Z%2|n z4Y$AlL9t^`ayxZ_JCeol40CDN4|>#5m4s>#dL2WRy=$t2s^Odldz~*6;DlxCwmAmo zvyCVcFhQk9Q_Gt)G8HBPkfrw4;l2Mr~l5c0QzrL%|H*j`he? zEdP~;ag5{87PCrFE$?c$5=ri#WIK8%=df-(y%NQ1nt^9%A_hXxZ*m@#qu(`ZO-1_rHog>2G{)Yqq;iyGvgp@tKOU|%F zr23PfC9cME%~@+2_L(AI7-ENVUz^SQ%YscLif84)penSS!Sd)?Z%7ZQ^)e3bH3&J? zHdOHlTWF){a*GM7f5memburhCu{5L>mQY;S?s+tO0j+V^l46c zdHE?ZRi{nl!_MBDg~`o|IYVyf1!-vQa`aUuhokA#aKxLV&3poaQSx#0=37}x8R8mf zBy-<{;L6^wLF_M|Kb*B!qyu8+Xfy?YaU;UGgUn&J^l)JhwsWPSg` z@RlO>W40UjhtN__?hieH#>{zUH$Zfr3Vl_`aWhT&fT>pE)1BBM^z=lC-1W z)L}ETBl@@{a>+w^_;~E5Q>vHl(bD}HJ43k`7M3{Ao5cJL3&qOOrYnsZr|yudk?A=%l8uD;`MKYS zz&+%Tr5zj}Uo`WhiowxQx>Za+AL7-kS2>lHm4kh09q2&XVWYB~kO~)_v@_{QPCZYf zxzuI~otM*y`k%DXRLi4J>+66%UWyDY)-y6i)JISdRNWN9=>8(j70HgiJIAe}+>d(i zgUV~(OqbYnxw|^MTE!ntpyPAk=3I-{ZY37p3 z=`)P(%ho^~^fMBq9^E@Zc%%paqr?f4$ZVw3O&c)FR7oyIT=nIBv)2(SWu0yxGPzpy zJ@!_Vf;ju-@YIu059YV4Z^iBw15AZ#O7#(EnuV%b-`CQ5sAjBI$WF_F^PFhYmjki%C@TKy+}HK<84ju{A!t|X^cDWd z_s(Ut2L*Kdy~n1(H(L=NmhO1y89l774voi>BAlll++uf)89n2HNEv>Hi{{f4*Yv! z|6YX>KQHu~LPv`*dyWrB7>W8HrVtubd<3}R z;aqzK4X!rWW+y*Y(O-b%^jmToCySl!y@;ZQ&5F7{?fdoUS}W#$x6g1)MO;SEEA3u| zTU?DDFW+%|;%lm}ueYsq97C6LghUB!#g|pwgtP_BEm%S_U)BpWP4>pE#{S~i@kMTEbDTN^M z^HZs1Q@qJ`Xp+Gh%QG4T~igEn}O_Z$r6Ct&o(T#egvGXxOBeO^`jUHynad?wb4 zh#^jNk5>)&NELJwTPb z!Dqt$hKc7l*XL+5$wHGtZ%dDFv#%(Dpc-u7*k z{$MyhQ_@JaKBQd`hM9PPM6-Za_)q9%D3B5dfvMp>nt|!NUYpdAotUlK>)d>LM+ zl0TBPmpfhPS|pSB@>*0Cv?TvVVm2*-D56Ht4~oRku>ewXROk!83VIs1KSF?2Gwxet zlqOCL!v_LaBR_Fd=(P_2)o4+_=F8{c>?S-oo3)~_Yz-%KgEla{Zbe~0 zvZefKhCA`v1=P6DWP23`!GWr2K^Odj+>R_P_8?GGh{k6s`h;2w;)GarXKqqINQJb$ z>o9b$0zHPXV)!x1X&I&on^Ho!7PJ?qtJD3@V`TpwAR>MZcFOR6vLK>%cM{NI(1A~Ft z5_D0lcsa(W5^0>ZxEc2{eLy{6p%$V{o8~)9ws;>J`tsT*(E9*p=4r4E+kc%IUj&L! z?PV1HS5_&SnE)IM&Dpv6`+q3Q4od+V2rH~Y(~nXC*tqWDI(8&}pvW@QT~M1Wpbziw z`~!djD3#M7S--h)13<@UXQ_W5P7Tk{3>+vKbMpopuCsEo?E8-2m=lu=t7=ZJP|%;Ln&3x2*->uq^H8pfW& z0DEVo!({3Doq$$C!mdA~0);}|xA;H&u$OF(cmY3mBETXXX$LMLmhs*NMT_nzKkD)0 zLE?W1U;2gbjp=iBb6s3y&@C!k0@lk#{XJBgt{P2guJIyw^gMFfN?$Q z4gcroud|VljJxk?T$YUEZ>FUZK}u>{uxxPPdGIq`y-oBAW6Uh{fs?pcn#QmO$V$ti zz>R5P7IWrevpw41EvfXR!+1*(!w?79ALM9Qvn7vS{w42xZhf?~a9CX#D(ru}Cn6*) zTwaZPEOES?Ugqy?3 zY>%~q${L;vArX<3YGfbUeS+hkdRUa!Rs`N{-r?U;?ZUv;6u%m!A%hSH;;*whk!Bf2 zKmwW4AtzaFXxJQNzH_|XLDg&0Gro4`slNWmFYxp7iVvdz-p@FFgh<98DQABvI^v0U?L1aud z12MCYXc{Ve@Fdb~3r39H)$BGWsu$8P28VsK)xiuO^(PY*T%3uyFZy*$;aY#LWTgar zK2fT^^lbfoPeqaVbTPymbFGo8`ljC2c9S)p3+`S+rd7`^j&A#fjDX+g#V1JWUqqCg z9xuGSQk+s29{fxccHqT5rT7N1C2XT&%a_|^H@#mkGL>yd`3q6wVYd>i%Bx%;l7FE# zO>RM_f)Gs8wF2xC(@(6f&B)1O&h@8(7|ZYlFImb)b9UrY*tNWt_^lk zX?%QKUHovueapiIUYK?#+1CuP8%gFz0liE^S}3!tT^1X5hAcv}B^anJVHd?hJw!>@ zkLR04imCYgdwCT>+is{@fFCe})D$1vDI2fCnXu9=$jUXH$ySvg(6YqyE^`x+lT`kCGZMr$6 z02P^MGA#1qGUU13DBs~7GTarAs*n}ST~B>>cJ_f(+18&Zme@w}(K9Dd)$X$D<({q& zz>Ytle*M&c`EzF)<&6@ARvNumGeNmXpZ;mKHTCF&dvWUe5vuwU!psJ1*!8|%j$4Jo zhQ=cx3S(>~mgBb{#MTuwoTJ5B;@GgzyN$xZ49)a)GYorc(j=yQG=8s{e7p6@KAtDX z+~MyL2(H{GcL3xKy~||HKB3-YTA-7pR;F0`QtvFa5N{oz6PddN?uH1Dpjpf_N2xL) z)8+}*^qaKW^2lk@#01@s`1#YVR|@{B?`8hg3o$IrxU;raSX)>YaCYoQF0PTEIw|Qq zQI+NEk>O%m26J{v09_Dt!9}+5z(6U&n6o*rr2CvP2A$OR04f`&QFQHp%9Kw0txI3=o2??GWijMPhzFCSlRzo z*g@~;=9NYz@!hH^OmN;M*GtDd?e+71mS)H-Gjmb4V9ca78=%H-WwPbVZ{V3#r4vg} zjg1{;`0{`l9whvWn7hr9rf(ymGP$Ha;JWWR|NMAAa|~lENEJPp`C!lZvPt4l^oNSF z&}1Iakan}CQ2)o_UUvd8Tzk3*MMOW7Pa&Y#A5*Kwy)P?!`){qbUGuy5H`11fiTNRX zeZ8r9=bz-zq@Dg}NHXUjJlxrTS-9W2GKFuy`0Jn1 z1;+2a$>CG?A{uOIOIwPl+4@L$?K97;;F@yXzX9Zx0pDL={&zhYXM;wW3C_9VOl92_ z%t|}S6BG8ta7)39VSvV<5faSlD%FcVI5?QxxKZZ*`$zQKRfgsNDub*mor~wV>vtnU~VPhNkOS40on=0<^y9tprF!45%Vd$m1BLpeRIYgU2 zv9$cHcSys}o$~Jj)@89t0JV#m+|GnrDYs<}ap@<3N&?H-8Gx5qT`iWTz> zib3IW27pB;to}9vwzV$)6Q9ms3vf;zISjU#_yFEWtWA;WSNpN}%te{s9b^ob{#xKz z)Rl5%43f0Cn1ay0)ckwUqbv{r#%5+(t9aTrVsCXKZyQ}+zhPUy9HuF5?NCd z^Br-o9*QzN+t}Kg-tAZAW6shyAwOR_-m1Fru{a9Y{c+Qy`@vN#DXySQ3z7HVRrG&;}ONz+W*x@NLReyK1!G}5@tYSOT9WDc)Y#cS`J#tLuJzwd zq>7T~p8ThhC!*vTe5Gcs&|N>X|9F2*RW+X1Q$JgAyw!_;gt0z~&6rWLawJ5|Djih@8kXD-xy2E*s zH5$amAVi5${yr=7aT@j0@pDG96zU-P1ab>K=L`0A;-n-Fp9ycCo`ceJbrULoV^`YJYHVjYYcM!qPjRUqMN zlsRv~IFZ|<)0Tj$ivRW`VQ#A9+Q#*v;o$>UC#tzAxfUSPH`Bpp2n)*h{2I_Kd$Hmc z4;)N7$TRfRR=y!-LieHFQzD=5+dy^6JSm+xDM+PdV!iCqD&FLUYk}iHKwDur@L%z6 zUo-rAB*A2(&=w2^`C!y8D@j0P*IP7^Lh^4ho&qSeBBZnsxXahv6Gjd?U_)iiE)geR zQF;feQ{V>vxD)ieP6wJC5*4x3*awa#R zhc$dJF*d-qRukNynGo|_9bEY@I7LcInt6VHuI=LDl9Qg^j9tT`9b2{yBhQ%?cgr$i zNJR}vQ8n)IfFjERZ(Tm}^hW@$bu77!kfBA zFe)fdz4(?j;P1EnwGq~_kr9y}*iR06A*>~Ae%k$T1FR`?DKK+Dy=GGu=8qmAO0XR! zQfA0X)=#~M&zSzxj40!HzNmo{7wy~h$X-E!G?+$#x-A--Pr6I&+UJASL!NBd`UV57 zTsTSw673Q-11n{LcX>93bMPEg#jrfH)gpf5(+rHhuTY^}epB9LK^fLc%Ll6^;qWdG zf*~OatlY~KdpV~%mBY0sqMEP zg`JvXyypYvN&b>?54gZbEX6u6thrVCMw25RFL2)NEVf%1bAI}CK(?l0YO@K|f}yE+R4AW-Lc^Ebg*Ei_yj0VHiey5F8D6Xc-nAJ?{|~D-hD`9&`-`zf zJpq@1uTHCU4DF+ z0rxRAL2~+ZQRH3y#ra8t+!n1?|21YOC#QQurSddw6m063gj?4WZWX-qD2`4t=>%A# z!$=|QGP&)Xl<{HR6qZ0ikmXwtn$ za+5ght;Xf(0q>T!#8X&>E^{0cI3&AC-UTzj*mPM-QC<21gLcc_EB%?Ec05m0P7(Q~ zD?u&a^EjCN-*=mP1^Yi9?3!Oz<==}E%9Nz)5})~M$sXfWOg75S;8Q;ztGax~<_Q>| z|Jw5-HW2wsgc=mjbmu(HQg^YlOSrZ8Z$PghW{2C;!=uUz3yvDBO-UY}&CF`pjF`Uj+dm9)%6U~j+XXTfVsNi%`Dm8yW?ySrlSJNM5 zhE|YN2GN$K2qo|5u9pM;3PS{c|3{l`kh&eHqZRTYv@Eg+h+{?!Th!enO+RqBC9eB& z+6?z}Ppq0M#dS1{d}5mzA3x6ay%F}6@3OV_;AoJMJh>^H*K~U1`P|N-x08jZ=?Yjq zNxP;HqIXr5f$e{F{%L7+##D*2Lh~dShmEmPQnl>u%pgsO6rcUY>+<~7{RC3CTwCQI-QG>9I8VX8YK8^HN>Vk1GHE9QhtUrBh?|pv-QvTpk>cBSXUF^15-+sgc&!Z=j5rj{ zr$r>3)baLK*K8IH!nOSNv2-95(@mWLNijc?1w?nmfFP;_d?eHNXZNn^=Wv5B(BDBe zi*?I3KjYc*SvJ?lFu1r@#kj0z`KB9yV`Ld3l5M7*`hE#JM$!(%^+h&%pt;F>1a!jp zW$=a@1`AQe&A5h=PLjj~x1@z6S$7?B!-E@%3GPt~DV(o< zn8?BKqFx*s>h{jJi(!8U#1%thttj-0^eOX%zH@iJcTXPj74=_mSGE7%m`F`qGg7>_;I7}>NphA@M4reVnRmTyY;Dpy-o%*42w`O85>@)Sb&Rna zad|*OW8X~0okxLaM6QXQw*=BhL(q$cuqzkpQDm4l)`OLG_t2u9t@6btHd+%jnNS-s zVP~N>P`&LHi|*49=9TRweGegAMA>kaVHN6oCg4NcbUJsMKXh@1%h z1-%gV8{gDBgT18!#Dc0HK*P96qco1w{KK@NJbmfK@#m`>q_)+Usz9FpB|vz4)+HQO zd)--34T7$kua5LDhMj(%+l#@F!|O^YdmD|c**p{ohmS9-`hln(tKS&T^jpeUcI@gt z8Tw0P9QZ1tDcNQr+Q(Mrt*)wz=vu2j2xcs;$Nz&v;a_z3R%7&0#GM}Pl2`K0 zGwK%_A88*BN9tg{=!QtyA01CryVDjKRjM;aTQz-tU|F%ZzrXRx#fD$(fQOf2(QM7rpL9&%)VV~@Ohc6yv?c;NcL8VM-4GK zh5sJgJ3{dhb`7pnJAG``XQ{|mVm=tmuF6@i@4_msK213u?DAbNX>$d+-b=fJxlfHp zP9$*?sp0k{hmNA;&E3ITfe#q`KiGYK*u|V7WT--Lx6`|-Jkce`^M@;y2WIyI>PmX# zu=^nx8ZI%w_}ckeOtFrn9d|wmF_=g@jhA@=tT)T3J<+8iqIJ(O`PJr^!QDX#`cp>( zCDz59zr^yr*HuLv5P3Or)IBddd&}&8+=B{t#TI<`g-(}%baoEQ0{A_%knu3IIzyu5 zz|IybgZ7(!p0Z?j*sh{IzvPYj&Yh_pT>+2gT>4`^#M^?WK|iACF?B^nTO7bU%@n)3 z!5EtQ;o)S5!^S#Pbzc6h{9g?G!su8)HTQ1>rxmu_&EbeUK*W%&?5>s{+@a2sGIQW} z`saD-9~jgt%rZ_QXO8E1T5<|)t=_W|{n<`?>^tg?h^$tR69Dv*o3~OS>GnP>`O1>3 z387Qf*~H>c&W&+-P-W`O4ZHY!b{GaWwEo?gl=OS9C=w|d!J#{J3=)Yg-eFpVg>q*f zz=Hdseok2l!vbGj4EAh$7h$d>V|GVz&QzY)&%$iUVwfKt=ohX?hIal2A1c8HBl~E( zd0^9J*;!hA{^2=))GPhQ(ZRa|8GNf3CCfeO`%U5p{KO3yWR-Vl>s#TP)$P2IZ-TM= zOX1JTWU+NFMjn)zU!sJZ`75%PLVfD~_(YydHbXlYqhI_v&aifgbbg%v_hRMErGvoS zdWVFLz9*34jScw7qO4`E3#4k(@jw}Zbc+z!Nl~9ct$xkz6BvRx^TlUIgMt-Z4LQn= z0OS$2)i#mS@8be9>Q!0D85E>9riCW&u3`qud-k?6d$cc-5oE&OZ-q)ppLLr$^z|3! z)&N Y -
Avatar Motion Tweaker
-
- - -
-
Crouch limit:
-
-
-
-
- -
-
- 0m -
-
-
-
-
-
- `; - - const targetElement = document.getElementById('btkUI-AvatarScaleMod-MainPage'); - if(targetElement) { - targetElement.appendChild(contentBlock); - } else { - console.warn('Target element "btkUI-AvatarScaleMod-MainPage" not found!'); + class MainContent { + constructor(targetId) { + this.element = document.createElement('div'); + this.element.id = "AvatarScaleModContainer"; + const targetElement = document.getElementById(targetId); + if (targetElement) { + targetElement.appendChild(this.element); + } else { + console.warn(`Target element "${targetId}" not found!`); + } } } /* ------------------------------- - * Event Handlers & Utility Functions + * Generic Element Class + * ------------------------------- */ + class Element { + constructor(tagName, parentElement) { + this.element = document.createElement(tagName); + parentElement.appendChild(this.element); + } + } + + /* ------------------------------- + * Container Object * ------------------------------- */ - { - const sliderContainer = document.querySelector('.avatar-scale-slider-container'); - const trackInner = document.querySelector('.avatar-scale-track-inner'); - const valueDisplay = document.querySelector('.slider-value'); + class Container extends Element { + constructor(parentElement, { + width = '100%', + padding = '0em', + paddingTop = null, + paddingRight = null, + paddingBottom = null, + paddingLeft = null, + margin = '0em', + marginTop = null, + marginRight = null, + marginBottom = null, + marginLeft = null + } = {}) { + super('div', parentElement); + this.element.className = "ass-container"; + this.element.style.width = width; + this.element.style.padding = padding; + this.element.style.margin = margin; - const SNAP_TOLERANCE = 0.02; - let snapPoints = []; + // padding values + if (paddingTop) this.element.style.paddingTop = paddingTop; + if (paddingRight) this.element.style.paddingRight = paddingRight; + if (paddingBottom) this.element.style.paddingBottom = paddingBottom; + if (paddingLeft) this.element.style.paddingLeft = paddingLeft; - let isDragging = false; + // margin values + if (marginTop) this.element.style.marginTop = marginTop; + if (marginRight) this.element.style.marginRight = marginRight; + if (marginBottom) this.element.style.marginBottom = marginBottom; + if (marginLeft) this.element.style.marginLeft = marginLeft; - sliderContainer.addEventListener('mousedown', (e) => { - isDragging = true; - updateTrackWidth(e.clientX); - }); + this.flexContainer = new Element('div', this.element); + this.flexContainer.element.className = "ass-flex-container"; + } - window.addEventListener('mousemove', (e) => { - if (!isDragging) return; - updateTrackWidth(e.clientX); - }); + appendElementToFlex(element) { + this.flexContainer.element.appendChild(element); + } - window.addEventListener('mouseup', () => { - isDragging = false; - }); + appendElement(element) { + this.element.appendChild(element); + } + } - function updateTrackWidth(clientX) { - const rect = sliderContainer.getBoundingClientRect(); + /* ------------------------------- + * Category (label) Class + * ------------------------------- */ + class Category extends Element { + constructor(parentElement, text) { + super('span', parentElement); + this.element.className = "ass-category-label"; + this.element.textContent = text; + } + } - // Get padding values from the slider container - const paddingLeft = parseFloat(getComputedStyle(sliderContainer).paddingLeft); - const paddingRight = parseFloat(getComputedStyle(sliderContainer).paddingRight); + /* ------------------------------- + * Circle Button Class + * ------------------------------- */ + class CircleButton extends Element { + constructor(parentElement, text) { + super('button', parentElement); + this.element.className = "ass-circle-button"; + this.element.textContent = text; + } + } - // Calculate the effective width and position based on padding + /* ------------------------------- + * Custom Toggle Class + * ------------------------------- */ + class CustomToggle extends Element { + constructor(parentElement) { + super('div', parentElement); + this.element.className = "ass-custom-toggle"; + + this.toggleCircle = new Element('div', this.element); + this.toggleCircle.element.className = "ass-toggle-circle"; + this.state = false; + + this.element.addEventListener('click', () => { + this.toggle(); + }); + } + + toggle() { + this.state = !this.state; + if (this.state) { + this.toggleCircle.element.style.left = '50%'; + } else { + this.toggleCircle.element.style.left = '0'; + } + } + } + + /* ------------------------------- + * Label Class + * ------------------------------- */ + class Label extends Element { + constructor(parentElement, text) { + super('span', parentElement); + this.element.className = "ass-label"; + this.element.textContent = text; + } + } + + /* ------------------------------- + * ToggleSetting Class + * ------------------------------- */ + class ToggleSetting extends Element { + constructor(parentElement, labelText) { + super('div', parentElement); + this.element.className = "ass-toggle-setting"; + + const label = new Label(this.element, labelText); + this.toggle = new CustomToggle(this.element); + } + } + + /* ------------------------------- + * Slider Object + * ------------------------------- */ + class Slider extends Element { + constructor(parentElement, min = 0.1, max = 5, initialValue = 1.8) { + super('div', parentElement); + this.element.className = "ass-slider-container"; + this.min = min; + this.max = max; + + // Value display + this.valueDisplay = new Element('span', this.element); + this.valueDisplay.element.className = "ass-slider-value"; + + // Slider content + this.sliderBase = new Element('div', this.element); + this.sliderBase.element.className = "ass-slider-base"; + + this.trackInner = new Element('div', this.sliderBase.element); + this.trackInner.element.className = "ass-slider-inner"; + + this.addEventListeners(); + + this.setInitialValue(initialValue); + } + + setInitialValue(value) { + const percentage = (value - this.min) / (this.max - this.min); + this.trackInner.element.style.width = `${percentage * 100}%`; + this.valueDisplay.element.textContent = value.toFixed(2) + "m"; + this.addSnapPoint(percentage); + } + + addEventListeners() { + this.snapPoints = []; + let isDragging = false; + + this.element.addEventListener('mousedown', (e) => { + isDragging = true; + this.updateTrackWidth(e.clientX); + }); + + window.addEventListener('mousemove', (e) => { + if (!isDragging) return; + this.updateTrackWidth(e.clientX); + }); + + window.addEventListener('mouseup', () => { + isDragging = false; + }); + } + + updateTrackWidth(clientX) { + const rect = this.element.getBoundingClientRect(); + const paddingLeft = parseFloat(getComputedStyle(this.element).paddingLeft); + const paddingRight = parseFloat(getComputedStyle(this.element).paddingRight); const effectiveWidth = rect.width - paddingLeft - paddingRight; let x = clientX - rect.left - paddingLeft; - // Ensure the position is within the bounds of the effective width x = Math.min(Math.max(0, x), effectiveWidth); - const percentage = x / effectiveWidth; - const closestSnap = snapPoints.reduce((closest, snap) => { + let percentage = x / effectiveWidth; + const closestSnap = this.snapPoints.reduce((closest, snap) => { return Math.abs(closest - percentage) < Math.abs(snap - percentage) ? closest : snap; }, 1); + const SNAP_TOLERANCE = 0.01; if (Math.abs(closestSnap - percentage) <= SNAP_TOLERANCE) { x = closestSnap * effectiveWidth; + percentage = closestSnap; } - trackInner.style.width = `${x}px`; - valueDisplay.textContent = (x / effectiveWidth * 100).toFixed(2) + "m"; + this.trackInner.element.style.width = `${x}px`; + + const value = this.min + (this.max - this.min) * percentage; + this.valueDisplay.element.textContent = value.toFixed(2) + "m"; + + engine.call("asm-AvatarHeightUpdated", value); } - function addSnapPoint(percentage) { + addSnapPoint(percentage) { if (percentage < 0 || percentage > 1) return; - const snap = document.createElement('div'); - snap.className = 'avatar-scale-snap-point'; - snap.style.left = `${percentage * 100}%`; - sliderContainer.appendChild(snap); - snapPoints.push(percentage); + const snap = new Element('div', this.sliderBase.element); + snap.element.className = 'ass-snap-point'; + snap.element.style.left = `${percentage * 100}%`; + this.snapPoints.push(percentage); } - // To evenly space out snap points: - function addEvenSnapPoints(count) { + addEvenSnapPoints(count) { for (let i = 1; i <= count; i++) { - addSnapPoint(i / (count + 1)); + this.addSnapPoint(i / (count + 1)); } } - - // Example usage: - addEvenSnapPoints(5); // Adds 5 evenly spaced snap points } + + // Initialization + injectCSS(); + const mainContent = new MainContent('btkUI-AvatarScaleMod-MainPage'); + if (mainContent.element) { + + const mainContainer = new Container(mainContent.element, { + width: '75%', + marginTop: '2em', + marginLeft: '2em', + marginBottom: '1em' + }); + + const slider = new Slider(mainContainer.flexContainer.element, 0.1, 3); + const buttonContainer = new Container(mainContainer.flexContainer.element, { + width: '20%', + marginTop: '2.5em', + marginLeft: '1em', + }); + const circleButton1 = new CircleButton(buttonContainer.flexContainer.element, "+"); + const circleButton2 = new CircleButton(buttonContainer.flexContainer.element, "-"); + + const settingsContainer = new Container(mainContent.element, { + width: '100%', + marginTop: '1em', + marginLeft: '1em', + }); + const categoryLabel = new Category(settingsContainer.element, "Universal Scaling Settings:"); + + const settingsContainerInner = new Container(mainContent.element, { + width: '90%', + marginTop: '1em', + marginLeft: '3em', + }); + + const toggleSetting = new ToggleSetting(settingsContainerInner.element, "Universal Scaling (Mod Network)"); + const toggleSetting2 = new ToggleSetting(settingsContainerInner.element, "Recognize Scale Gesture"); + const toggleSetting3 = new ToggleSetting(settingsContainerInner.element, "Scale Components"); + } + })(); \ No newline at end of file diff --git a/AvatarScale/resources/nak_menu.css b/AvatarScale/resources/nak_menu.css deleted file mode 100644 index d732c3d..0000000 --- a/AvatarScale/resources/nak_menu.css +++ /dev/null @@ -1,13 +0,0 @@ -.slider-container { - margin: 10px 0; - padding: 5px; -} - -.slider-label { - display: block; - margin-bottom: 5px; -} - -.test-slider { - width: 100%; -}