Check for props game settings and world restrictions

Combat system integration
Additional measure for unsafe worlds
This commit is contained in:
SDraw 2023-04-12 21:33:25 +03:00
parent 5185c00fb1
commit 912b37c87f
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
9 changed files with 186 additions and 57 deletions

View file

@ -7,7 +7,7 @@ Merged set of MelonLoader mods for ChilloutVR.
| Avatar Motion Tweaker | ml_amt | 1.2.5 | Yes, update review | Working | | Avatar Motion Tweaker | ml_amt | 1.2.5 | Yes, update review | Working |
| Desktop Head Tracking | ml_dht | 1.1.2 | Yes | Working | | Desktop Head Tracking | ml_dht | 1.1.2 | Yes | Working |
| Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working |
| Extended Game Notifications | ml_egn | 1.0.1 | Yes | Working | Extended Game Notifications | ml_egn | 1.0.2 | Yes, update review | Working
| Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update
| Leap Motion Extension | ml_lme | 1.3.3 | Yes | Working | | Leap Motion Extension | ml_lme | 1.3.3 | Yes | Working |
| Pickup Arm Movement | ml_pam | 1.0.2 | Yes| Working | | Pickup Arm Movement | ml_pam | 1.0.2 | Yes| Working |

View file

@ -1,5 +1,4 @@
using ABI_RC.Core.EventSystem; using ABI_RC.Core.EventSystem;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.IO; using ABI_RC.Core.IO;
using ABI_RC.Core.Networking; using ABI_RC.Core.Networking;
using ABI_RC.Core.Util; using ABI_RC.Core.Util;
@ -57,6 +56,7 @@ namespace ml_egn
Utils.ShowMenuNotification("Avatar changed", 1f); Utils.ShowMenuNotification("Avatar changed", 1f);
else else
Utils.ShowHUDNotification("(Synced) Client", "Avatar changed"); Utils.ShowHUDNotification("(Synced) Client", "Avatar changed");
} }
catch(System.Exception e) catch(System.Exception e)
{ {
@ -68,19 +68,37 @@ namespace ml_egn
{ {
try try
{ {
if(Utils.IsConnected()) if(Utils.ArePropsEnabled())
{ {
if(Utils.IsMenuOpened()) if(Utils.ArePropsAllowed())
Utils.ShowMenuNotification("Prop spawned", 1f); {
if(Utils.IsConnected())
{
if(Utils.IsMenuOpened())
Utils.ShowMenuNotification("Prop spawned", 1f);
else
Utils.ShowHUDNotification("(Synced) Client", "Prop spawned");
}
else
{
if(Utils.IsMenuOpened())
Utils.ShowMenuAlert("Prop Error", "Not connected to live instance");
else
Utils.ShowHUDNotification("(Local) Client", "Unable to spawn prop", "Not connected to live instance");
}
}
else else
Utils.ShowHUDNotification("(Synced) Client", "Prop spawned"); {
if(Utils.IsMenuOpened())
Utils.ShowMenuAlert("Prop Error", "Props are not allowed in this world");
}
} }
else else
{ {
if(Utils.IsMenuOpened()) if(Utils.IsMenuOpened())
Utils.ShowMenuAlert("Prop Error", "Not connected to live instance"); Utils.ShowMenuAlert("Prop Error", "Props are disabled in game settings");
else else
Utils.ShowHUDNotification("(Local) Client", "Unable to spawn prop", "Not connected to live instance"); Utils.ShowHUDNotification("(Local) Client", "Unable to spawn prop", "Props are disabled in game settings");
} }
} }
catch(System.Exception e) catch(System.Exception e)

View file

@ -1,10 +1,10 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyTitle("ExtendedGameNotifications")] [assembly: AssemblyTitle("ExtendedGameNotifications")]
[assembly: AssemblyVersion("1.0.1")] [assembly: AssemblyVersion("1.0.2")]
[assembly: AssemblyFileVersion("1.0.1")] [assembly: AssemblyFileVersion("1.0.2")]
[assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]

View file

@ -1,5 +1,6 @@
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Networking; using ABI_RC.Core.Networking;
using ABI_RC.Core.Savior;
using ABI_RC.Core.UI; using ABI_RC.Core.UI;
using DarkRift; using DarkRift;
@ -42,5 +43,8 @@ namespace ml_egn
l_result = (NetworkManager.Instance.GameNetwork.ConnectionState == ConnectionState.Connected); l_result = (NetworkManager.Instance.GameNetwork.ConnectionState == ConnectionState.Connected);
return l_result; return l_result;
} }
public static bool ArePropsAllowed() => ((MetaPort.Instance != null) && MetaPort.Instance.worldAllowProps);
public static bool ArePropsEnabled() => ((MetaPort.Instance != null) && MetaPort.Instance.settings.GetSettingsBool("ContentFilterPropsEnabled"));
} }
} }

View file

@ -6,6 +6,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using ABI_RC.Core.Util.AssetFiltering; using ABI_RC.Core.Util.AssetFiltering;
using ABI.CCK.Components;
using System.Linq;
namespace ml_prm namespace ml_prm
{ {
@ -47,6 +49,11 @@ namespace ml_prm
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null null
); );
HarmonyInstance.Patch(
typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))),
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
// Whitelist the toggle script // Whitelist the toggle script
(typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) as HashSet<Type>)?.Add(typeof(RagdollToggle)); (typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) as HashSet<Type>)?.Add(typeof(RagdollToggle));
@ -140,5 +147,22 @@ namespace ml_prm
} }
} }
static void OnCombatDown_Prefix(ref CombatSystem __instance)
{
if((__instance == CombatSystem.Instance) && !__instance.isDown)
ms_instance?.OnCombatDown();
}
void OnCombatDown()
{
try
{
if(m_localController != null)
m_localController.OnCombatDown();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
} }
} }

View file

@ -16,6 +16,7 @@ Optional mod's settings with [BTKUILib](https://github.com/BTK-Development/BTKUI
* **Use gravity:** enables/disables gravity for ragdoll; `true` by default. * **Use gravity:** enables/disables gravity for ragdoll; `true` by default.
* Note: Forcibly enabled in worlds that don't allow flight. * Note: Forcibly enabled in worlds that don't allow flight.
* **Pointers reaction:** enables ragdoll state when player collides with CVRPointer colliders of `ragdoll` type (avatars, props and world included); `true` by default. * **Pointers reaction:** enables ragdoll state when player collides with CVRPointer colliders of `ragdoll` type (avatars, props and world included); `true` by default.
* **Combat reaction:** enables ragdoll state upon death in worlds with combat system; `true` by default.
* **Velocity multiplier:** velocity force multiplier based on player's movement direction; `2.0` by default. * **Velocity multiplier:** velocity force multiplier based on player's movement direction; `2.0` by default.
* Note: Limited according to world's fly multiplier. * Note: Limited according to world's fly multiplier.
* Note: Forcibly set to `1.0` in worlds that don't allow flight. * Note: Forcibly set to `1.0` in worlds that don't allow flight.

View file

@ -1,4 +1,5 @@
using ABI_RC.Core.InteractionSystem; using ABI.CCK.Components;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.MovementSystem; using ABI_RC.Systems.MovementSystem;
@ -33,6 +34,8 @@ namespace ml_prm
RagdollToggle m_avatarRagdollToggle = null; RagdollToggle m_avatarRagdollToggle = null;
RagdollTrigger m_customTrigger = null; RagdollTrigger m_customTrigger = null;
bool m_reachedGround = true;
internal RagdollController() internal RagdollController()
{ {
if(Instance == null) if(Instance == null)
@ -84,15 +87,18 @@ namespace ml_prm
m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f; m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f;
m_lastPosition = l_pos; m_lastPosition = l_pos;
if(m_avatarReady && !m_reachedGround && MovementSystem.Instance.IsGrounded())
m_reachedGround = true;
if(m_enabled && m_avatarReady && BodySystem.isCalibratedAsFullBody)
BodySystem.TrackingPositionWeight = 0f;
if(Settings.Hotkey && Input.GetKeyDown(KeyCode.R) && !ViewManager.Instance.isGameMenuOpen()) if(Settings.Hotkey && Input.GetKeyDown(KeyCode.R) && !ViewManager.Instance.isGameMenuOpen())
SwitchRagdoll(); SwitchRagdoll();
if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_enabled != m_avatarRagdollToggle.isOn)) if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_enabled != m_avatarRagdollToggle.isOn))
SwitchRagdoll(); SwitchRagdoll();
if(m_enabled && m_avatarReady && BodySystem.isCalibratedAsFullBody)
BodySystem.TrackingPositionWeight = 0f;
if((m_customTrigger != null) && m_customTrigger.GetStateWithReset() && !m_enabled && m_avatarReady && Settings.PointersReaction) if((m_customTrigger != null) && m_customTrigger.GetStateWithReset() && !m_enabled && m_avatarReady && Settings.PointersReaction)
SwitchRagdoll(); SwitchRagdoll();
} }
@ -127,6 +133,7 @@ namespace ml_prm
m_colliders.Clear(); m_colliders.Clear();
m_puppetReferences = new BipedRagdollReferences(); m_puppetReferences = new BipedRagdollReferences();
m_boneLinks.Clear(); m_boneLinks.Clear();
m_reachedGround = true;
} }
internal void OnAvatarSetup() internal void OnAvatarSetup()
@ -253,6 +260,12 @@ namespace ml_prm
} }
} }
internal void OnCombatDown()
{
if(!m_enabled && m_avatarReady && Settings.CombatReaction)
SwitchRagdoll();
}
// IK updates // IK updates
void OnIKPreUpdate() void OnIKPreUpdate()
{ {
@ -305,60 +318,88 @@ namespace ml_prm
// Arbitrary // Arbitrary
public void SwitchRagdoll() public void SwitchRagdoll()
{ {
if(m_avatarReady && (MovementSystem.Instance.lastSeat == null) && !BodySystem.isCalibrating) if(m_avatarReady)
{ {
m_enabled = !m_enabled; if(!m_enabled)
MovementSystem.Instance.SetImmobilized(m_enabled);
if(m_enabled)
{ {
PlayerSetup.Instance.animatorManager.SetAnimatorParameterTrigger("CancelEmote"); if(IsSafeToRagdoll() && m_reachedGround)
if(BodySystem.isCalibratedAsFullBody)
BodySystem.TrackingPositionWeight = 0f;
// Copy before set to non-kinematic to reduce stacked forces
foreach(var l_link in m_boneLinks)
l_link.Item2.CopyGlobal(l_link.Item1);
foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = false;
Vector3 l_velocity = m_velocity * Mathf.Clamp(Settings.VelocityMultiplier, 1f, (Utils.IsWorldSafe() ? Utils.GetWorldFlyMultiplier() : 1f));
foreach(Rigidbody l_body in m_rigidBodies)
{ {
l_body.velocity = l_velocity; // Eject player from seat
l_body.angularVelocity = Vector3.zero; if(MovementSystem.Instance.lastSeat != null)
{
Vector3 l_pos = PlayerSetup.Instance.transform.position;
Quaternion l_rot = PlayerSetup.Instance.transform.rotation;
MovementSystem.Instance.lastSeat.ExitSeat();
PlayerSetup.Instance.transform.position = l_pos;
PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f);
}
MovementSystem.Instance.SetImmobilized(true);
PlayerSetup.Instance.animatorManager.SetAnimatorParameterTrigger("CancelEmote");
if(BodySystem.isCalibratedAsFullBody)
BodySystem.TrackingPositionWeight = 0f;
if(!Utils.IsWorldSafe())
m_reachedGround = false; // Force player to unragdoll and reach ground first
// Copy before set to non-kinematic to reduce stacked forces
foreach(var l_link in m_boneLinks)
l_link.Item2.CopyGlobal(l_link.Item1);
foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = false;
Vector3 l_velocity = m_velocity * Mathf.Clamp(Settings.VelocityMultiplier, 1f, (Utils.IsWorldSafe() ? Utils.GetWorldFlyMultiplier() : 1f));
foreach(Rigidbody l_body in m_rigidBodies)
{
l_body.velocity = l_velocity;
l_body.angularVelocity = Vector3.zero;
}
foreach(Collider l_collider in m_colliders)
l_collider.enabled = true;
m_enabled = true;
} }
} }
else else
{ {
if(BodySystem.isCalibratedAsFullBody) if(IsSafeToUnragdoll())
BodySystem.TrackingPositionWeight = 1f;
foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = true;
if(m_puppetReferences.hips != null)
{ {
Vector3 l_hipsPos = m_puppetReferences.hips.position; MovementSystem.Instance.SetImmobilized(false);
if(BodySystem.isCalibratedAsFullBody)
BodySystem.TrackingPositionWeight = 1f;
if(!Settings.RestorePosition) foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = true;
if(m_puppetReferences.hips != null)
{ {
if(Utils.IsInVR()) Vector3 l_hipsPos = m_puppetReferences.hips.position;
if(!Settings.RestorePosition)
{ {
Vector3 l_diff = l_hipsPos - PlayerSetup.Instance._avatar.transform.position; if(Utils.IsInVR())
Vector3 l_playerPos = PlayerSetup.Instance.transform.position; {
PlayerSetup.Instance.transform.position = l_playerPos + l_diff; Vector3 l_diff = l_hipsPos - PlayerSetup.Instance._avatar.transform.position;
Vector3 l_playerPos = PlayerSetup.Instance.transform.position;
PlayerSetup.Instance.transform.position = l_playerPos + l_diff;
}
else
PlayerSetup.Instance.transform.position = l_hipsPos;
} }
else
PlayerSetup.Instance.transform.position = l_hipsPos;
} }
foreach(Collider l_collider in m_colliders)
l_collider.enabled = false;
m_lastPosition = PlayerSetup.Instance.transform.position;
m_velocity = Vector3.zero;
m_enabled = false;
} }
} }
foreach(Collider l_collider in m_colliders)
l_collider.enabled = m_enabled;
} }
} }
@ -371,5 +412,20 @@ namespace ml_prm
p_source.CopyGlobal(l_target); p_source.CopyGlobal(l_target);
return l_target; return l_target;
} }
static bool IsSafeToRagdoll()
{
bool l_result = true;
l_result &= !BodySystem.isCalibrating; // Not calibrating
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
return l_result;
}
static bool IsSafeToUnragdoll()
{
bool l_result = true;
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
return l_result;
}
} }
} }

View file

@ -14,7 +14,8 @@ namespace ml_prm
MovementDrag, MovementDrag,
AngularDrag, AngularDrag,
Gravity, Gravity,
PointersReaction PointersReaction,
CombatReaction
} }
enum UiElementIndex enum UiElementIndex
@ -23,6 +24,7 @@ namespace ml_prm
RestorePosition, RestorePosition,
Gravity, Gravity,
PointersReaction, PointersReaction,
CombatReaction,
VelocityMultiplier, VelocityMultiplier,
MovementDrag, MovementDrag,
AngularDrag AngularDrag
@ -35,6 +37,7 @@ namespace ml_prm
public static float AngularDrag { get; private set; } = 2f; public static float AngularDrag { get; private set; } = 2f;
public static bool Gravity { get; private set; } = true; public static bool Gravity { get; private set; } = true;
public static bool PointersReaction { get; private set; } = true; public static bool PointersReaction { get; private set; } = true;
public static bool CombatReaction { get; private set; } = true;
static public event Action SwitchChange; static public event Action SwitchChange;
static public event Action<bool> HotkeyChange; static public event Action<bool> HotkeyChange;
@ -44,6 +47,7 @@ namespace ml_prm
static public event Action<float> AngularDragChange; static public event Action<float> AngularDragChange;
static public event Action<bool> GravityChange; static public event Action<bool> GravityChange;
static public event Action<bool> PointersReactionChange; static public event Action<bool> PointersReactionChange;
static public event Action<bool> CombatReactionChange;
static MelonLoader.MelonPreferences_Category ms_category = null; static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null; static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
@ -61,7 +65,8 @@ namespace ml_prm
ms_category.CreateEntry(ModSetting.MovementDrag.ToString(), MovementDrag), ms_category.CreateEntry(ModSetting.MovementDrag.ToString(), MovementDrag),
ms_category.CreateEntry(ModSetting.AngularDrag.ToString(), AngularDrag), ms_category.CreateEntry(ModSetting.AngularDrag.ToString(), AngularDrag),
ms_category.CreateEntry(ModSetting.Gravity.ToString(), Gravity), ms_category.CreateEntry(ModSetting.Gravity.ToString(), Gravity),
ms_category.CreateEntry(ModSetting.PointersReaction.ToString(), PointersReaction) ms_category.CreateEntry(ModSetting.PointersReaction.ToString(), PointersReaction),
ms_category.CreateEntry(ModSetting.CombatReaction.ToString(), CombatReaction)
}; };
Hotkey = (bool)ms_entries[(int)ModSetting.Hotkey].BoxedValue; Hotkey = (bool)ms_entries[(int)ModSetting.Hotkey].BoxedValue;
@ -71,6 +76,7 @@ namespace ml_prm
AngularDrag = UnityEngine.Mathf.Clamp((float)ms_entries[(int)ModSetting.MovementDrag].BoxedValue, 0f, 50f); AngularDrag = UnityEngine.Mathf.Clamp((float)ms_entries[(int)ModSetting.MovementDrag].BoxedValue, 0f, 50f);
Gravity = (bool)ms_entries[(int)ModSetting.Gravity].BoxedValue; Gravity = (bool)ms_entries[(int)ModSetting.Gravity].BoxedValue;
PointersReaction = (bool)ms_entries[(int)ModSetting.PointersReaction].BoxedValue; PointersReaction = (bool)ms_entries[(int)ModSetting.PointersReaction].BoxedValue;
CombatReaction = (bool)ms_entries[(int)ModSetting.CombatReaction].BoxedValue;
if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "BTKUILib") != null) if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "BTKUILib") != null)
{ {
@ -122,6 +128,14 @@ namespace ml_prm
PointersReactionChange?.Invoke(state); PointersReactionChange?.Invoke(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) =>
{
CombatReaction = state;
ms_entries[(int)ModSetting.CombatReaction].BoxedValue = state;
CombatReactionChange?.Invoke(state);
};
ms_uiElements.Add(l_page.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", VelocityMultiplier, 1f, 50f)); 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) => (ms_uiElements[(int)UiElementIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) =>
{ {
@ -168,6 +182,11 @@ namespace ml_prm
(ms_uiElements[(int)UiElementIndex.PointersReaction] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = true; (ms_uiElements[(int)UiElementIndex.PointersReaction] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = true;
PointersReactionChange?.Invoke(true); PointersReactionChange?.Invoke(true);
CombatReaction = true;
ms_entries[(int)ModSetting.CombatReaction].BoxedValue = true;
(ms_uiElements[(int)UiElementIndex.CombatReaction] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = true;
CombatReactionChange?.Invoke(true);
VelocityMultiplier = 2f; VelocityMultiplier = 2f;
ms_entries[(int)ModSetting.VelocityMultiplier].BoxedValue = 2f; ms_entries[(int)ModSetting.VelocityMultiplier].BoxedValue = 2f;
(ms_uiElements[(int)UiElementIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(2f); (ms_uiElements[(int)UiElementIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(2f);

View file

@ -1,11 +1,16 @@
using ABI.CCK.Components; using ABI.CCK.Components;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.MovementSystem;
using System.Reflection;
using UnityEngine; using UnityEngine;
namespace ml_prm namespace ml_prm
{ {
static class Utils static class Utils
{ {
public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); static readonly FieldInfo ms_grounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance);
public static bool IsInVR() => ((CheckVR.Instance != null) && CheckVR.Instance.hasVrDeviceLoaded);
public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying); public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
public static float GetWorldFlyMultiplier() public static float GetWorldFlyMultiplier()
{ {
@ -15,6 +20,8 @@ namespace ml_prm
return l_result; return l_result;
} }
public static bool IsGrounded(this MovementSystem p_instance) => (bool)ms_grounded.GetValue(p_instance);
public static void CopyGlobal(this Transform p_source, Transform p_target) public static void CopyGlobal(this Transform p_source, Transform p_target)
{ {
p_target.position = p_source.position; p_target.position = p_source.position;