From 6d13ff18947e79f00881ada3bf052fc92503beb4 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 29 Apr 2023 03:18:45 +0300 Subject: [PATCH] Dedicated BTKUILib page Internal settings and UI rework Upcoming mod support --- README.md | 4 +- ml_amt/ModSupporter.cs | 17 +++ ml_amt/Properties/AssemblyInfo.cs | 8 +- ml_amt/ml_amt.csproj | 4 + ml_prm/Main.cs | 8 ++ ml_prm/ModUi.cs | 189 ++++++++++++++++++++++++++++++ ml_prm/Properties/AssemblyInfo.cs | 6 +- ml_prm/README.md | 2 +- ml_prm/RagdollController.cs | 10 +- ml_prm/Settings.cs | 170 ++++++--------------------- ml_prm/ml_prm.csproj | 5 +- ml_prm/resources/person.png | Bin 0 -> 5017 bytes 12 files changed, 269 insertions(+), 154 deletions(-) create mode 100644 ml_prm/ModUi.cs create mode 100644 ml_prm/resources/person.png diff --git a/README.md b/README.md index d266da0..d0fbc08 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ Merged set of MelonLoader mods for ChilloutVR. | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes | |-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------| | Avatar Change Info | ml_aci | 1.0.3 | Retired | Retired | Superseded by `Extended Game Notifications` -| Avatar Motion Tweaker | ml_amt | 1.2.6 | Yes | Working | +| Avatar Motion Tweaker | ml_amt | 1.2.7 | Yes, update review | Working | | Desktop Head Tracking | ml_dht | 1.1.3 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Extended Game Notifications | ml_egn | 1.0.2 | Yes | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Leap Motion Extension | ml_lme | 1.3.4 | Yes | Working | | Pickup Arm Movement | ml_pam | 1.0.3 | Yes | Working | -| Player Ragdoll Mod | ml_prm | 1.0.1 | Yes | Working | +| Player Ragdoll Mod | ml_prm | 1.0.2 | Yes, update review | Working | | Server Connection Info | ml_sci | 1.0.2 | Retired | Retired | Superseded by `Extended Game Notifications` diff --git a/ml_amt/ModSupporter.cs b/ml_amt/ModSupporter.cs index c5c2ed5..a453e86 100644 --- a/ml_amt/ModSupporter.cs +++ b/ml_amt/ModSupporter.cs @@ -6,11 +6,14 @@ namespace ml_amt static class ModSupporter { static bool ms_ragdollMod = false; + static bool ms_copycatMod = false; public static void Init() { if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "PlayerRagdollMod") != null) MelonLoader.MelonCoroutines.Start(WaitForRagdollInstance()); + if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "PlayerMovementCopycat") != null) + MelonLoader.MelonCoroutines.Start(WaitForCopycatInstance()); } // PlayerRagdollMod support @@ -22,11 +25,25 @@ namespace ml_amt ms_ragdollMod = true; } static bool IsRagdolled() => ml_prm.RagdollController.Instance.IsRagdolled(); + + // PlayerMovementCopycat support + static IEnumerator WaitForCopycatInstance() + { + while(ml_pmc.PoseCopycat.Instance == null) + yield return null; + + ms_copycatMod = true; + } + static bool IsCopycating() => ml_pmc.PoseCopycat.Instance.IsActive(); + public static bool SkipHipsOverride() { bool l_result = false; l_result |= (ms_ragdollMod && IsRagdolled()); + l_result |= (ms_copycatMod && IsCopycating()); return l_result; } + + } } diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index e187bdd..2a256a4 100644 --- a/ml_amt/Properties/AssemblyInfo.cs +++ b/ml_amt/Properties/AssemblyInfo.cs @@ -1,11 +1,11 @@ using System.Reflection; [assembly: AssemblyTitle("AvatarMotionTweaker")] -[assembly: AssemblyVersion("1.2.6")] -[assembly: AssemblyFileVersion("1.2.6")] +[assembly: AssemblyVersion("1.2.7")] +[assembly: AssemblyFileVersion("1.2.7")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.6", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] -[assembly: MelonLoader.MelonOptionalDependencies("ml_prm")] +[assembly: MelonLoader.MelonOptionalDependencies("ml_prm", "ml_pmc")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] \ No newline at end of file diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index 17bb8f2..58d618a 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -54,6 +54,10 @@ False False + + D:\Games\Steam\steamapps\common\ChilloutVR\Mods\ml_pmc.dll + False + D:\Games\Steam\steamapps\common\ChilloutVR\Mods\ml_prm.dll False diff --git a/ml_prm/Main.cs b/ml_prm/Main.cs index cb01968..0ab7447 100644 --- a/ml_prm/Main.cs +++ b/ml_prm/Main.cs @@ -24,6 +24,7 @@ namespace ml_prm ms_instance = this; Settings.Init(); + ModUi.Init(); HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), @@ -81,6 +82,13 @@ namespace ml_prm yield return null; m_localController = PlayerSetup.Instance.gameObject.AddComponent(); + ModUi.SwitchChange += this.OnSwitchActivation; + } + + void OnSwitchActivation() + { + if(m_localController != null) + m_localController.SwitchRagdoll(); } // Patches diff --git a/ml_prm/ModUi.cs b/ml_prm/ModUi.cs new file mode 100644 index 0000000..1c50179 --- /dev/null +++ b/ml_prm/ModUi.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace ml_prm +{ + static class ModUi + { + enum UiIndex + { + Hotkey = 0, + Gravity, + PointersReaction, + IgnoreLocal, + CombatReaction, + AutoRecover, + Slipperiness, + Bounciness, + ViewVelocity, + VelocityMultiplier, + MovementDrag, + AngularDrag, + RecoverDelay + } + + static public event Action SwitchChange; + + static List ms_uiElements = null; + + internal static void Init() + { + ms_uiElements = new List(); + + if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "BTKUILib") != null) + CreateUi(); + } + + // Separated method, otherwise exception is thrown, funny CSharp and optional references, smh + static void CreateUi() + { + BTKUILib.QuickMenuAPI.PrepareIcon("PlayerRagdollMod", "PRM-Person", GetIconStream("person.png")); + + var l_modRoot = new BTKUILib.UIObjects.Page("PlayerRagdollMod", "MainPage", true, "PRM-Person"); + l_modRoot.MenuTitle = "Player Ragdoll Mod"; + l_modRoot.MenuSubtitle = "Become a ragdoll and change various settings for people amusement"; + + var l_modCategory = l_modRoot.AddCategory("Settings"); + + l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state").OnPress += () => SwitchChange?.Invoke(); + + ms_uiElements.Add(l_modCategory.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Settings.Hotkey)); + (ms_uiElements[(int)UiIndex.Hotkey] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state); + + ms_uiElements.Add(l_modCategory.AddToggle("Use gravity", "Apply gravity to ragdoll", Settings.Gravity)); + (ms_uiElements[(int)UiIndex.Gravity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Gravity, state); + + ms_uiElements.Add(l_modCategory.AddToggle("Pointers reaction", "React to trigger colliders with CVRPointer component of 'ragdoll' type", Settings.PointersReaction)); + (ms_uiElements[(int)UiIndex.PointersReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.PointersReaction, state); + + ms_uiElements.Add(l_modCategory.AddToggle("Ignore local pointers", "Ignore local avatar's CVRPointer components of 'ragdoll' type", Settings.IgnoreLocal)); + (ms_uiElements[(int)UiIndex.IgnoreLocal] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.IgnoreLocal, state); + + ms_uiElements.Add(l_modCategory.AddToggle("Combat reaction", "Ragdoll upon combat system death", Settings.CombatReaction)); + (ms_uiElements[(int)UiIndex.CombatReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.CombatReaction, state); + + ms_uiElements.Add(l_modCategory.AddToggle("Auto recover", "Automatically unragdoll after set recover delay", Settings.AutoRecover)); + (ms_uiElements[(int)UiIndex.AutoRecover] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.AutoRecover, state); + + ms_uiElements.Add(l_modCategory.AddToggle("Slipperiness", "Enables/disables friction of ragdoll", Settings.Slipperiness)); + (ms_uiElements[(int)UiIndex.Slipperiness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Slipperiness, state); + + ms_uiElements.Add(l_modCategory.AddToggle("Bounciness", "Enables/disables bounciness of ragdoll", Settings.Bounciness)); + (ms_uiElements[(int)UiIndex.Bounciness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Bounciness, state); + + ms_uiElements.Add(l_modCategory.AddToggle("View direction velocity", "Apply velocity to camera view direction", Settings.ViewVelocity)); + (ms_uiElements[(int)UiIndex.ViewVelocity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.ViewVelocity, state); + + ms_uiElements.Add(l_modRoot.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f)); + (ms_uiElements[(int)UiIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value); + + ms_uiElements.Add(l_modRoot.AddSlider("Movement drag", "Movement resistance", Settings.MovementDrag, 0f, 50f)); + (ms_uiElements[(int)UiIndex.MovementDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.MovementDrag, value); + + ms_uiElements.Add(l_modRoot.AddSlider("Angular movement drag", "Rotation movement resistance", Settings.AngularDrag, 0f, 50f)); + (ms_uiElements[(int)UiIndex.AngularDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.AngularDrag, value); + + ms_uiElements.Add(l_modRoot.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", Settings.RecoverDelay, 1f, 10f)); + (ms_uiElements[(int)UiIndex.RecoverDelay] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.RecoverDelay, value); + + l_modCategory.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset; + } + + static void OnToggleUpdate(UiIndex p_index, bool p_state, bool p_force = false) + { + switch(p_index) + { + case UiIndex.Hotkey: + Settings.SetSetting(Settings.ModSetting.Hotkey, p_state); + break; + + case UiIndex.Gravity: + Settings.SetSetting(Settings.ModSetting.Gravity, p_state); + break; + + case UiIndex.PointersReaction: + Settings.SetSetting(Settings.ModSetting.PointersReaction, p_state); + break; + + case UiIndex.IgnoreLocal: + Settings.SetSetting(Settings.ModSetting.IgnoreLocal, p_state); + break; + + case UiIndex.CombatReaction: + Settings.SetSetting(Settings.ModSetting.CombatReaction, p_state); + break; + + case UiIndex.AutoRecover: + Settings.SetSetting(Settings.ModSetting.AutoRecover, p_state); + break; + + case UiIndex.Slipperiness: + Settings.SetSetting(Settings.ModSetting.Slipperiness, p_state); + break; + + case UiIndex.Bounciness: + Settings.SetSetting(Settings.ModSetting.Bounciness, p_state); + break; + + case UiIndex.ViewVelocity: + Settings.SetSetting(Settings.ModSetting.ViewVelocity, p_state); + break; + } + + if(p_force) + (ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state; + } + + static void OnSliderUpdate(UiIndex p_index, float p_value, bool p_force = false) + { + switch(p_index) + { + case UiIndex.VelocityMultiplier: + Settings.SetSetting(Settings.ModSetting.VelocityMultiplier, p_value); + break; + + case UiIndex.MovementDrag: + Settings.SetSetting(Settings.ModSetting.MovementDrag, p_value); + break; + + case UiIndex.AngularDrag: + Settings.SetSetting(Settings.ModSetting.AngularDrag, p_value); + break; + + case UiIndex.RecoverDelay: + Settings.SetSetting(Settings.ModSetting.RecoverDelay, p_value); + break; + } + + if(p_force) + (ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value); + } + + static void Reset() + { + OnToggleUpdate(UiIndex.Hotkey, true, true); + OnToggleUpdate(UiIndex.Gravity, true, true); + OnToggleUpdate(UiIndex.PointersReaction, true, true); + OnToggleUpdate(UiIndex.IgnoreLocal, true, true); + OnToggleUpdate(UiIndex.CombatReaction, true, true); + OnToggleUpdate(UiIndex.AutoRecover, false, true); + OnToggleUpdate(UiIndex.Slipperiness, false, true); + OnToggleUpdate(UiIndex.Bounciness, false, true); + OnToggleUpdate(UiIndex.ViewVelocity, false, true); + OnSliderUpdate(UiIndex.VelocityMultiplier, 2f, true); + OnSliderUpdate(UiIndex.MovementDrag, 2f, true); + OnSliderUpdate(UiIndex.AngularDrag, 2f, true); + OnSliderUpdate(UiIndex.RecoverDelay, 3f, true); + } + + static Stream GetIconStream(string p_name) + { + Assembly l_assembly = Assembly.GetExecutingAssembly(); + string l_assemblyName = l_assembly.GetName().Name; + return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + } + } +} diff --git a/ml_prm/Properties/AssemblyInfo.cs b/ml_prm/Properties/AssemblyInfo.cs index dca7ef0..511e79b 100644 --- a/ml_prm/Properties/AssemblyInfo.cs +++ b/ml_prm/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("PlayerRagdollMod")] -[assembly: AssemblyVersion("1.0.1")] -[assembly: AssemblyFileVersion("1.0.1")] +[assembly: AssemblyVersion("1.0.2")] +[assembly: AssemblyFileVersion("1.0.2")] -[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPriority(2)] [assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")] diff --git a/ml_prm/README.md b/ml_prm/README.md index ba900d3..df89e18 100644 --- a/ml_prm/README.md +++ b/ml_prm/README.md @@ -9,7 +9,7 @@ This mod turns player's avatar into ragdoll puppet. # Usage * Press `R` to turn into ragdoll and back. -Optional mod's settings with [BTKUILib](https://github.com/BTK-Development/BTKUILib): +Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/BTKUILib): * **Switch ragdoll:** turns into ragdoll state and back, made for VR usage primarily. * **Use hotkey:** enables/disables ragdoll state switch with `R` key; `true` by default. * **Use gravity:** enables/disables gravity for ragdoll; `true` by default. diff --git a/ml_prm/RagdollController.cs b/ml_prm/RagdollController.cs index 35f56cd..51cc3c0 100644 --- a/ml_prm/RagdollController.cs +++ b/ml_prm/RagdollController.cs @@ -76,7 +76,6 @@ namespace ml_prm m_customTrigger = MovementSystem.Instance.proxyCollider.gameObject.AddComponent(); - Settings.SwitchChange += this.SwitchRagdoll; Settings.MovementDragChange += this.OnMovementDragChange; Settings.AngularDragChange += this.OnAngularDragChange; Settings.GravityChange += this.OnGravityChange; @@ -92,7 +91,6 @@ namespace ml_prm m_customTrigger = null; } - Settings.SwitchChange -= this.SwitchRagdoll; Settings.MovementDragChange -= this.OnMovementDragChange; Settings.AngularDragChange -= this.OnAngularDragChange; Settings.GravityChange -= this.OnGravityChange; @@ -224,10 +222,6 @@ namespace ml_prm l_options.joints = RagdollCreator.JointType.Character; BipedRagdollCreator.Create(m_puppetReferences, l_options); - // And return back - m_puppetRoot.localPosition = Vector3.zero; - m_puppetRoot.localRotation = Quaternion.identity; - Transform[] l_puppetTransforms = m_puppetReferences.GetRagdollTransforms(); Transform[] l_avatarTransforms = l_avatarReferences.GetRagdollTransforms(); for(int i = 0; i < l_puppetTransforms.Length; i++) @@ -269,6 +263,10 @@ namespace ml_prm } } + // And return back + m_puppetRoot.localPosition = Vector3.zero; + m_puppetRoot.localRotation = Quaternion.identity; + m_vrIK = PlayerSetup.Instance._avatar.GetComponent(); if(m_vrIK != null) { diff --git a/ml_prm/Settings.cs b/ml_prm/Settings.cs index dcbed8b..5f6d824 100644 --- a/ml_prm/Settings.cs +++ b/ml_prm/Settings.cs @@ -7,7 +7,7 @@ namespace ml_prm { static class Settings { - enum ModSetting + public enum ModSetting { Hotkey = 0, VelocityMultiplier, @@ -24,25 +24,6 @@ namespace ml_prm ViewVelocity } - enum UiElementIndex - { - Hotkey = 0, - Gravity, - PointersReaction, - IgnoreLocal, - CombatReaction, - AutoRecover, - Slipperiness, - Bounciness, - ViewVelocity, - VelocityMultiplier, - MovementDrag, - AngularDrag, - RecoverDelay, - - Count - } - public static bool Hotkey { get; private set; } = true; public static float VelocityMultiplier { get; private set; } = 2f; public static float MovementDrag { get; private set; } = 2f; @@ -57,7 +38,6 @@ namespace ml_prm public static bool Bounciness { get; private set; } = false; public static bool ViewVelocity { get; private set; } = false; - static public event Action SwitchChange; static public event Action HotkeyChange; static public event Action VelocityMultiplierChange; static public event Action MovementDragChange; @@ -75,8 +55,6 @@ namespace ml_prm static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; - static List ms_uiElements = new List(); - internal static void Init() { ms_category = MelonLoader.MelonPreferences.CreateCategory("PRM", null, true); @@ -110,190 +88,108 @@ namespace ml_prm Slipperiness = (bool)ms_entries[(int)ModSetting.Slipperiness].BoxedValue; Bounciness = (bool)ms_entries[(int)ModSetting.Bounciness].BoxedValue; ViewVelocity = (bool)ms_entries[(int)ModSetting.ViewVelocity].BoxedValue; - - if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "BTKUILib") != null) - { - CreateBtkUi(); - } } - static void CreateBtkUi() + public static void SetSetting(ModSetting p_settings, object p_value) { - var l_categoryMain = BTKUILib.QuickMenuAPI.MiscTabPage.AddCategory("PlayerRagdollMod"); - var l_page = l_categoryMain.AddPage("Player Ragdoll Settings", "", "PlayerRagdollMod settings", "PlayerRagdollMod"); - l_page.MenuTitle = "Ragdoll settings"; - var l_categoryMod = l_page.AddCategory("Settings"); - - l_categoryMod.AddButton("Switch ragdoll", "", "Switch between normal and ragdoll state").OnPress += () => SwitchChange?.Invoke(); - - ms_uiElements.Add(l_categoryMod.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Hotkey)); - (ms_uiElements[(int)UiElementIndex.Hotkey] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.Hotkey, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("Use gravity", "Apply gravity to ragdoll", Gravity)); - (ms_uiElements[(int)UiElementIndex.Gravity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.Gravity, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("Pointers reaction", "React to trigger colliders with CVRPointer component of 'ragdoll' type", PointersReaction)); - (ms_uiElements[(int)UiElementIndex.PointersReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.PointersReaction, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("Ignore local pointers", "Ignore local avatar's CVRPointer components of 'ragdoll' type", IgnoreLocal)); - (ms_uiElements[(int)UiElementIndex.IgnoreLocal] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.IgnoreLocal, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("Combat reaction", "Ragdoll upon combat system death", CombatReaction)); - (ms_uiElements[(int)UiElementIndex.CombatReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.CombatReaction, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("Auto recover", "Automatically unragdoll after set recover delay", AutoRecover)); - (ms_uiElements[(int)UiElementIndex.AutoRecover] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.AutoRecover, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("Slipperiness", "Enables/disables friction of ragdoll", Slipperiness)); - (ms_uiElements[(int)UiElementIndex.Slipperiness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.Slipperiness, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("Bounciness", "Enables/disables bounciness of ragdoll", Bounciness)); - (ms_uiElements[(int)UiElementIndex.Bounciness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.Bounciness, state); - - ms_uiElements.Add(l_categoryMod.AddToggle("View direction velocity", "Apply velocity to camera view direction", ViewVelocity)); - (ms_uiElements[(int)UiElementIndex.ViewVelocity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(ModSetting.ViewVelocity, state); - - ms_uiElements.Add(l_page.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", VelocityMultiplier, 1f, 50f)); - (ms_uiElements[(int)UiElementIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(ModSetting.VelocityMultiplier, value); - - ms_uiElements.Add(l_page.AddSlider("Movement drag", "Movement resistance", MovementDrag, 0f, 50f)); - (ms_uiElements[(int)UiElementIndex.MovementDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(ModSetting.MovementDrag, value); - - ms_uiElements.Add(l_page.AddSlider("Angular movement drag", "Rotation movement resistance", AngularDrag, 0f, 50f)); - (ms_uiElements[(int)UiElementIndex.AngularDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(ModSetting.AngularDrag, value); - - ms_uiElements.Add(l_page.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", RecoverDelay, 1f, 10f)); - (ms_uiElements[(int)UiElementIndex.RecoverDelay] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(ModSetting.RecoverDelay, value); - - l_categoryMod.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset; - } - - static void OnToggleUpdate(ModSetting p_setting, bool p_state, UiElementIndex p_uiIndex = UiElementIndex.Count) - { - switch(p_setting) + switch(p_settings) { + // Booleans case ModSetting.Hotkey: { - Hotkey = p_state; - HotkeyChange?.Invoke(p_state); + Hotkey = (bool)p_value; + HotkeyChange?.Invoke((bool)p_value); } break; case ModSetting.Gravity: { - Gravity = p_state; - GravityChange?.Invoke(p_state); + Gravity = (bool)p_value; + GravityChange?.Invoke((bool)p_value); } break; case ModSetting.PointersReaction: { - PointersReaction = p_state; - PointersReactionChange?.Invoke(p_state); + PointersReaction = (bool)p_value; + PointersReactionChange?.Invoke((bool)p_value); } break; case ModSetting.IgnoreLocal: { - IgnoreLocal = p_state; - IgnoreLocalChange?.Invoke(p_state); + IgnoreLocal = (bool)p_value; + IgnoreLocalChange?.Invoke((bool)p_value); } break; case ModSetting.CombatReaction: { - CombatReaction = p_state; - CombatReactionChange?.Invoke(p_state); + CombatReaction = (bool)p_value; + CombatReactionChange?.Invoke((bool)p_value); } break; case ModSetting.AutoRecover: { - AutoRecover = p_state; - AutoRecoverChange?.Invoke(p_state); + AutoRecover = (bool)p_value; + AutoRecoverChange?.Invoke((bool)p_value); } break; case ModSetting.Slipperiness: { - Slipperiness = p_state; - SlipperinessChange?.Invoke(p_state); + Slipperiness = (bool)p_value; + SlipperinessChange?.Invoke((bool)p_value); } break; case ModSetting.Bounciness: { - Bounciness = p_state; - BouncinessChange?.Invoke(p_state); + Bounciness = (bool)p_value; + BouncinessChange?.Invoke((bool)p_value); } break; case ModSetting.ViewVelocity: { - ViewVelocity = p_state; - ViewVelocityChange?.Invoke(p_state); + ViewVelocity = (bool)p_value; + ViewVelocityChange?.Invoke((bool)p_value); } break; - } - ms_entries[(int)p_setting].BoxedValue = p_state; - if(p_uiIndex != UiElementIndex.Count) - (ms_uiElements[(int)p_uiIndex] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state; - } - - static void OnSliderUpdate(ModSetting p_setting, float p_value, UiElementIndex p_uiIndex = UiElementIndex.Count) - { - switch(p_setting) - { + // Floats case ModSetting.VelocityMultiplier: { - VelocityMultiplier = p_value; - VelocityMultiplierChange?.Invoke(p_value); + VelocityMultiplier = (float)p_value; + VelocityMultiplierChange?.Invoke((float)p_value); } break; case ModSetting.MovementDrag: { - MovementDrag = p_value; - MovementDragChange?.Invoke(p_value); + MovementDrag = (float)p_value; + MovementDragChange?.Invoke((float)p_value); } break; case ModSetting.AngularDrag: { - AngularDrag = p_value; - AngularDragChange?.Invoke(p_value); + AngularDrag = (float)p_value; + AngularDragChange?.Invoke((float)p_value); } break; case ModSetting.RecoverDelay: { - RecoverDelay = p_value; - RecoverDelayChange?.Invoke(p_value); + RecoverDelay = (float)p_value; + RecoverDelayChange?.Invoke((float)p_value); } break; } - ms_entries[(int)p_setting].BoxedValue = p_value; - if(p_uiIndex != UiElementIndex.Count) - (ms_uiElements[(int)p_uiIndex] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value); - } - - static void Reset() - { - OnToggleUpdate(ModSetting.Hotkey, true, UiElementIndex.Hotkey); - OnToggleUpdate(ModSetting.Gravity, true, UiElementIndex.Gravity); - OnToggleUpdate(ModSetting.PointersReaction, true, UiElementIndex.PointersReaction); - OnToggleUpdate(ModSetting.IgnoreLocal, true, UiElementIndex.IgnoreLocal); - OnToggleUpdate(ModSetting.CombatReaction, true, UiElementIndex.CombatReaction); - OnToggleUpdate(ModSetting.AutoRecover, false, UiElementIndex.AutoRecover); - OnToggleUpdate(ModSetting.Slipperiness, false, UiElementIndex.Slipperiness); - OnToggleUpdate(ModSetting.Bounciness, false, UiElementIndex.Bounciness); - OnToggleUpdate(ModSetting.ViewVelocity, false, UiElementIndex.ViewVelocity); - OnSliderUpdate(ModSetting.VelocityMultiplier, 2f, UiElementIndex.VelocityMultiplier); - OnSliderUpdate(ModSetting.MovementDrag, 2f, UiElementIndex.MovementDrag); - OnSliderUpdate(ModSetting.AngularDrag, 2f, UiElementIndex.AngularDrag); - OnSliderUpdate(ModSetting.RecoverDelay, 3f, UiElementIndex.RecoverDelay); + if(ms_entries != null) + ms_entries[(int)p_settings].BoxedValue = p_value; } } } diff --git a/ml_prm/ml_prm.csproj b/ml_prm/ml_prm.csproj index 33450f6..c7743ae 100644 --- a/ml_prm/ml_prm.csproj +++ b/ml_prm/ml_prm.csproj @@ -87,6 +87,7 @@ + @@ -135,7 +136,9 @@ - + + + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" diff --git a/ml_prm/resources/person.png b/ml_prm/resources/person.png new file mode 100644 index 0000000000000000000000000000000000000000..578c19777cfb21a7109615266570ea456989ee7a GIT binary patch literal 5017 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 vXK#@!zE1Kd(yq8kNnH4U{Ez_f`T+xSRDSn