Propper game events

Ragdoll body parts grab
This commit is contained in:
SDraw 2024-08-10 15:29:40 +03:00
parent 8bead6a764
commit 84c255660e
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
12 changed files with 279 additions and 20 deletions

View file

@ -24,8 +24,8 @@ namespace ml_pin
{ {
m_soundManager = null; m_soundManager = null;
CVRGameEventSystem.Player.OnJoin.RemoveListener(OnPlayerJoin); CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(OnPlayerJoin);
CVRGameEventSystem.Player.OnLeave.RemoveListener(OnPlayerLeave); CVRGameEventSystem.Player.OnLeaveEntity.RemoveListener(OnPlayerLeave);
} }
IEnumerator WaitForInstances() IEnumerator WaitForInstances()
@ -36,17 +36,17 @@ namespace ml_pin
m_soundManager = new SoundManager(); m_soundManager = new SoundManager();
m_soundManager.LoadSounds(); m_soundManager.LoadSounds();
CVRGameEventSystem.Player.OnJoin.AddListener(OnPlayerJoin); CVRGameEventSystem.Player.OnJoinEntity.AddListener(OnPlayerJoin);
CVRGameEventSystem.Player.OnLeave.AddListener(OnPlayerLeave); CVRGameEventSystem.Player.OnLeaveEntity.AddListener(OnPlayerLeave);
} }
void OnPlayerJoin(PlayerDescriptor p_player) void OnPlayerJoin(CVRPlayerEntity p_player)
{ {
try try
{ {
if(p_player != null) // This happens sometimes, no idea why if((p_player != null) && (p_player.PlayerDescriptor != null)) // This happens sometimes, no idea why
{ {
bool l_isFriend = Friends.FriendsWith(p_player.ownerId); bool l_isFriend = Friends.FriendsWith(p_player.PlayerDescriptor.ownerId);
bool l_notify = false; bool l_notify = false;
switch(Settings.NotifyType) switch(Settings.NotifyType)
@ -72,13 +72,13 @@ namespace ml_pin
MelonLoader.MelonLogger.Warning(e); MelonLoader.MelonLogger.Warning(e);
} }
} }
void OnPlayerLeave(PlayerDescriptor p_player) void OnPlayerLeave(CVRPlayerEntity p_player)
{ {
try try
{ {
if(p_player != null) // This happens sometimes, no idea why if((p_player != null) && (p_player.PlayerDescriptor != null)) // This happens sometimes, no idea why
{ {
bool l_isFriend = Friends.FriendsWith(p_player.ownerId); bool l_isFriend = Friends.FriendsWith(p_player.PlayerDescriptor.ownerId);
bool l_notify = false; bool l_notify = false;
switch(Settings.NotifyType) switch(Settings.NotifyType)

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.8", "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

@ -7,7 +7,7 @@
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>None</Company> <Company>None</Company>
<Product>PlayersInstanceNotifier</Product> <Product>PlayersInstanceNotifier</Product>
<Version>1.0.7</Version> <Version>1.0.8</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View file

@ -1,5 +1,6 @@
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Core.Util.AssetFiltering; using ABI_RC.Core.Util.AssetFiltering;
using ABI_RC.Systems.GameEventSystem;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -17,6 +18,8 @@ namespace ml_prm
GameEvents.Init(HarmonyInstance); GameEvents.Init(HarmonyInstance);
WorldHandler.Init(); WorldHandler.Init();
CVRGameEventSystem.Player.OnJoinEntity.AddListener(this.OnRemotePlayerCreated);
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
MelonLoader.MelonCoroutines.Start(WaitForWhitelist()); MelonLoader.MelonCoroutines.Start(WaitForWhitelist());
} }
@ -28,6 +31,8 @@ namespace ml_prm
if(m_localController != null) if(m_localController != null)
UnityEngine.Object.Destroy(m_localController); UnityEngine.Object.Destroy(m_localController);
m_localController = null; m_localController = null;
CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(this.OnRemotePlayerCreated);
} }
System.Collections.IEnumerator WaitForLocalPlayer() System.Collections.IEnumerator WaitForLocalPlayer()
@ -50,5 +55,11 @@ namespace ml_prm
} }
l_hashSet.Add(typeof(RagdollToggle)); l_hashSet.Add(typeof(RagdollToggle));
} }
void OnRemotePlayerCreated(CVRPlayerEntity p_player)
{
if((p_player != null) && (p_player.PuppetMaster != null))
p_player.PuppetMaster.gameObject.AddComponent<RemoteGestureHandler>();
}
} }
} }

View file

@ -34,7 +34,10 @@ namespace ml_prm
MovementDrag, MovementDrag,
AngularDrag, AngularDrag,
RecoverDelay, RecoverDelay,
FallLimit FallLimit,
GestureGrab,
FriendsGrab,
GrabDistance
} }
const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key"; const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key";
@ -58,11 +61,14 @@ namespace ml_prm
static ToggleButton ms_jumpRecoverToggle = null; static ToggleButton ms_jumpRecoverToggle = null;
static ToggleButton ms_buoyancyToggle = null; static ToggleButton ms_buoyancyToggle = null;
static ToggleButton ms_fallDamageToggle = null; static ToggleButton ms_fallDamageToggle = null;
static ToggleButton ms_gestureGrabToggle = null;
static ToggleButton ms_friendsGrabToggle = null;
static SliderFloat ms_velocityMultiplierSlider = null; static SliderFloat ms_velocityMultiplierSlider = null;
static SliderFloat ms_movementDragSlider = null; static SliderFloat ms_movementDragSlider = null;
static SliderFloat ms_angularMovementDragSlider = null; static SliderFloat ms_angularMovementDragSlider = null;
static SliderFloat ms_recoverDelaySlider = null; static SliderFloat ms_recoverDelaySlider = null;
static SliderFloat ms_fallLimitSlider = null; static SliderFloat ms_fallLimitSlider = null;
static SliderFloat ms_grabDistanceSlider = null;
static Button ms_resetButton = null; static Button ms_resetButton = null;
internal static void Init() internal static void Init()
@ -77,7 +83,7 @@ namespace ml_prm
ms_ragdollButton = ms_category.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state"); ms_ragdollButton = ms_category.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state");
ms_ragdollButton.OnPress += OnSwitch; ms_ragdollButton.OnPress += OnSwitch;
ms_hotkeyToggle = ms_category.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Settings.Hotkey); ms_hotkeyToggle = ms_category.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Settings.Hotkey);
ms_hotkeyToggle.ToggleTooltip = string.Format(c_ragdollKeyTooltip, Settings.HotkeyKey); ms_hotkeyToggle.ToggleTooltip = string.Format(c_ragdollKeyTooltip, Settings.HotkeyKey);
ms_hotkeyToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state); ms_hotkeyToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state);
@ -116,6 +122,12 @@ namespace ml_prm
ms_fallDamageToggle = ms_category.AddToggle("Fall damage", "Enable ragdoll when falling from height", Settings.FallDamage); ms_fallDamageToggle = ms_category.AddToggle("Fall damage", "Enable ragdoll when falling from height", Settings.FallDamage);
ms_fallDamageToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FallDamage, state); ms_fallDamageToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FallDamage, state);
ms_gestureGrabToggle = ms_category.AddToggle("Gesture grab", "Enable grabbing of ragdolled body parts by remote players with trigger gesture<p>Warning: can lead to unpredictable physics behaviour in some cases", Settings.GestureGrab);
ms_gestureGrabToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.GestureGrab, state);
ms_friendsGrabToggle = ms_category.AddToggle("Friends grab only", " ", Settings.FriendsGrab);
ms_friendsGrabToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FriendsGrab, state);
ms_velocityMultiplierSlider = ms_category.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f); ms_velocityMultiplierSlider = ms_category.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f);
ms_velocityMultiplierSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value); ms_velocityMultiplierSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value);
@ -132,6 +144,9 @@ namespace ml_prm
ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(Settings.FallLimit)); ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(Settings.FallLimit));
ms_fallLimitSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value); ms_fallLimitSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value);
ms_grabDistanceSlider = ms_category.AddSlider("Grab distance", "Minimal distance for successful grab", Settings.GrabDistance, 0f, 1f);
ms_grabDistanceSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.GrabDistance, value);
ms_resetButton = ms_category.AddButton("Reset settings", "", "Reset mod settings to default"); ms_resetButton = ms_category.AddButton("Reset settings", "", "Reset mod settings to default");
ms_resetButton.OnPress += Reset; ms_resetButton.OnPress += Reset;
} }
@ -201,6 +216,14 @@ namespace ml_prm
case UiIndex.FallDamage: case UiIndex.FallDamage:
Settings.SetSetting(Settings.ModSetting.FallDamage, p_state); Settings.SetSetting(Settings.ModSetting.FallDamage, p_state);
break; break;
case UiIndex.GestureGrab:
Settings.SetSetting(Settings.ModSetting.GestureGrab, p_state);
break;
case UiIndex.FriendsGrab:
Settings.SetSetting(Settings.ModSetting.FriendsGrab, p_state);
break;
} }
} }
catch(Exception e) catch(Exception e)
@ -237,6 +260,10 @@ namespace ml_prm
ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(p_value)); ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(p_value));
} }
break; break;
case UiIndex.GrabDistance:
Settings.SetSetting(Settings.ModSetting.GrabDistance, p_value);
break;
} }
} }
catch(Exception e) catch(Exception e)
@ -283,6 +310,12 @@ namespace ml_prm
OnToggleUpdate(UiIndex.FallDamage, true); OnToggleUpdate(UiIndex.FallDamage, true);
ms_fallDamageToggle.ToggleValue = true; ms_fallDamageToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.GestureGrab, false);
ms_gestureGrabToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.FriendsGrab, true);
ms_friendsGrabToggle.ToggleValue = true;
OnSliderUpdate(UiIndex.VelocityMultiplier, 2f); OnSliderUpdate(UiIndex.VelocityMultiplier, 2f);
ms_velocityMultiplierSlider.SetSliderValue(2f); ms_velocityMultiplierSlider.SetSliderValue(2f);
@ -297,6 +330,9 @@ namespace ml_prm
OnSliderUpdate(UiIndex.FallLimit, 9.899494f); OnSliderUpdate(UiIndex.FallLimit, 9.899494f);
ms_fallLimitSlider.SetSliderValue(9.899494f); ms_fallLimitSlider.SetSliderValue(9.899494f);
OnSliderUpdate(UiIndex.GrabDistance, 0.1f);
ms_grabDistanceSlider.SetSliderValue(0.1f);
} }
static void OnHotkeyKeyChanged(UnityEngine.KeyCode p_keyCode) static void OnHotkeyKeyChanged(UnityEngine.KeyCode p_keyCode)

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(2)] [assembly: MelonLoader.MelonPriority(2)]
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")] [assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]

View file

@ -29,6 +29,9 @@ Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/
* **Buoyancy:** enables floating in fluid volumes; `true` by default. * **Buoyancy:** enables floating in fluid volumes; `true` by default.
* Note: Forcibly enabled in worlds that don't allow flight. * Note: Forcibly enabled in worlds that don't allow flight.
* **Fall damage:** enables ragdoll when falling from specific height; `true` by default. * **Fall damage:** enables ragdoll when falling from specific height; `true` by default.
* **Gesture grab:** enables grabbing of ragdolled body parts by remote players with trigger gesture; `false` by default.
* Note: Can lead to unpredictable physics behaviour in some cases.
* **Friends grab only:** Allow only friends to be able to grab your radgolled body parts; `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.
@ -37,6 +40,7 @@ Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/
* **Angular movement drag:** angular movement resistance; `2.0` by default. * **Angular movement drag:** angular movement resistance; `2.0` by default.
* **Recover delay:** time delay for enabled `Auto recover` in seconds; `3.0` by default. * **Recover delay:** time delay for enabled `Auto recover` in seconds; `3.0` by default.
* **Fall limit:** height limit for fall damage; `5.0` by default. * **Fall limit:** height limit for fall damage; `5.0` by default.
* **Grab distance:** minimal distance for successful grab; `0.1` by default.
* **Reset settings:** resets mod settings to default. * **Reset settings:** resets mod settings to default.
Optional mod's settings in [UIExpansionKit](https://github.com/ddakebono/ChilloutMods): Optional mod's settings in [UIExpansionKit](https://github.com/ddakebono/ChilloutMods):

View file

@ -18,6 +18,11 @@ namespace ml_prm
bool m_shouldHaveInfluencer = false; bool m_shouldHaveInfluencer = false;
bool m_activeGravity = true; bool m_activeGravity = true;
bool m_attached = false;
Transform m_attachedHand = null;
Transform m_attachTransform = null;
FixedJoint m_attachJoint = null;
// Unity events // Unity events
void Awake() void Awake()
{ {
@ -72,6 +77,8 @@ namespace ml_prm
{ {
if(collider != null) if(collider != null)
CVRParticlePointerManager.RemoveTrigger(collider); CVRParticlePointerManager.RemoveTrigger(collider);
Detach();
} }
void FixedUpdate() void FixedUpdate()
@ -80,11 +87,26 @@ namespace ml_prm
{ {
m_rigidBody.useGravity = false; m_rigidBody.useGravity = false;
if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged())) if(!m_attached && m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass); m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
} }
} }
void Update()
{
if(m_attached && !ReferenceEquals(m_attachTransform, null) && (m_attachTransform == null))
{
m_attachTransform = null;
if(m_attachJoint != null)
Object.Destroy(m_attachJoint);
m_attachJoint = null;
m_attachedHand = null;
m_attached = false;
}
}
void OnTriggerEnter(Collider p_col) void OnTriggerEnter(Collider p_col)
{ {
if(Settings.PointersReaction && (RagdollController.Instance != null)) if(Settings.PointersReaction && (RagdollController.Instance != null))
@ -178,6 +200,54 @@ namespace ml_prm
return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform)); return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform));
} }
public bool Attach(Transform p_hand, Vector3 p_pos)
{
bool l_result = false;
if(!m_attached && (collider != null))
{
if(Vector3.Distance(p_pos, collider.ClosestPoint(p_pos)) <= Settings.GrabDistance)
{
GameObject l_attachPoint = new GameObject("[AttachPoint]");
m_attachTransform = l_attachPoint.transform;
m_attachTransform.parent = p_hand;
m_attachTransform.position = p_pos;
Rigidbody l_body = l_attachPoint.AddComponent<Rigidbody>();
l_body.isKinematic = true;
l_body.detectCollisions = false;
m_attachJoint = this.gameObject.AddComponent<FixedJoint>();
m_attachJoint.connectedBody = l_body;
m_attachJoint.breakForce = Mathf.Infinity;
m_attachJoint.breakTorque = Mathf.Infinity;
m_attached = true;
m_attachedHand = p_hand;
l_result = true;
}
}
return l_result;
}
public void Detach() => Detach(m_attachedHand);
public void Detach(Transform p_hand)
{
if(m_attached && ReferenceEquals(m_attachedHand, p_hand))
{
if(m_attachTransform != null)
Object.Destroy(m_attachTransform.gameObject);
m_attachTransform = null;
if(m_attachJoint != null)
Object.Destroy(m_attachJoint);
m_attachJoint = null;
m_attachedHand = null;
m_attached = false;
}
}
// CVRTriggerVolume // CVRTriggerVolume
public void TriggerEnter(CVRPointer pointer) public void TriggerEnter(CVRPointer pointer)
{ {
@ -187,6 +257,8 @@ namespace ml_prm
RagdollController.Instance.SwitchRagdoll(); RagdollController.Instance.SwitchRagdoll();
} }
} }
public void TriggerExit(CVRPointer pointer) { } public void TriggerExit(CVRPointer pointer)
{
}
} }
} }

View file

@ -88,6 +88,7 @@ namespace ml_prm
Settings.OnBouncinessChanged.AddHandler(this.OnPhysicsMaterialChanged); Settings.OnBouncinessChanged.AddHandler(this.OnPhysicsMaterialChanged);
Settings.OnBuoyancyChanged.AddHandler(this.OnBuoyancyChanged); Settings.OnBuoyancyChanged.AddHandler(this.OnBuoyancyChanged);
Settings.OnFallDamageChanged.AddHandler(this.OnFallDamageChanged); Settings.OnFallDamageChanged.AddHandler(this.OnFallDamageChanged);
Settings.OnGestureGrabChanged.AddHandler(this.OnGestureGrabChanged);
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear); GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup); GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
@ -103,6 +104,7 @@ namespace ml_prm
BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport); BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport);
ModUi.OnSwitchChanged.AddHandler(this.SwitchRagdoll); ModUi.OnSwitchChanged.AddHandler(this.SwitchRagdoll);
RemoteGestureHandler.OnGestureState.AddHandler(this.OnRemotePlayerGestureStateChanged);
} }
void OnDestroy() void OnDestroy()
@ -135,6 +137,7 @@ namespace ml_prm
Settings.OnBouncinessChanged.RemoveHandler(this.OnPhysicsMaterialChanged); Settings.OnBouncinessChanged.RemoveHandler(this.OnPhysicsMaterialChanged);
Settings.OnBuoyancyChanged.RemoveHandler(this.OnBuoyancyChanged); Settings.OnBuoyancyChanged.RemoveHandler(this.OnBuoyancyChanged);
Settings.OnFallDamageChanged.RemoveHandler(this.OnFallDamageChanged); Settings.OnFallDamageChanged.RemoveHandler(this.OnFallDamageChanged);
Settings.OnGestureGrabChanged.RemoveHandler(this.OnGestureGrabChanged);
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear); GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup); GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
@ -150,6 +153,7 @@ namespace ml_prm
BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport); BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport);
ModUi.OnSwitchChanged.RemoveHandler(this.SwitchRagdoll); ModUi.OnSwitchChanged.RemoveHandler(this.SwitchRagdoll);
RemoteGestureHandler.OnGestureState.RemoveHandler(this.OnRemotePlayerGestureStateChanged);
} }
void Update() void Update()
@ -485,6 +489,37 @@ namespace ml_prm
p_result.m_result |= (m_enabled && (m_vrIK != null)); p_result.m_result |= (m_enabled && (m_vrIK != null));
} }
// Custom game events
void OnRemotePlayerGestureStateChanged(ABI_RC.Core.Player.PuppetMaster p_master, bool p_left, bool p_state)
{
if(m_avatarReady && m_enabled && Settings.GestureGrab && (p_master.animatorManager.Animator != null))
{
Transform l_hand = p_master.animatorManager.Animator.GetBoneTransform(p_left ? HumanBodyBones.LeftHand : HumanBodyBones.RightHand);
Transform l_finger = p_master.animatorManager.Animator.GetBoneTransform(p_left ? HumanBodyBones.LeftMiddleProximal : HumanBodyBones.RightMiddleProximal);
if(l_hand != null)
{
Vector3 l_pos = l_hand.position;
if(l_finger != null)
{
l_pos += l_finger.position;
l_pos *= 0.5f;
}
foreach(var l_bodyHandler in m_ragdollBodyHandlers)
{
if(p_state)
{
if(l_bodyHandler.Attach(l_hand, l_pos))
break;
}
else
l_bodyHandler.Detach(l_hand);
}
}
}
}
// VRIK updates // VRIK updates
void OnIKPostSolverUpdate() void OnIKPostSolverUpdate()
{ {
@ -505,6 +540,7 @@ namespace ml_prm
l_handler.SetDrag(l_drag); l_handler.SetDrag(l_drag);
} }
} }
void OnAngularDragChanged(float p_value) void OnAngularDragChanged(float p_value)
{ {
if(m_avatarReady) if(m_avatarReady)
@ -513,6 +549,7 @@ namespace ml_prm
l_handler.SetAngularDrag(p_value); l_handler.SetAngularDrag(p_value);
} }
} }
void OnGravityChanged(bool p_state) void OnGravityChanged(bool p_state)
{ {
if(m_avatarReady) if(m_avatarReady)
@ -528,6 +565,7 @@ namespace ml_prm
} }
} }
} }
void OnPhysicsMaterialChanged(bool p_state) void OnPhysicsMaterialChanged(bool p_state)
{ {
if(m_physicsMaterial != null) if(m_physicsMaterial != null)
@ -541,6 +579,7 @@ namespace ml_prm
m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average); m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average);
} }
} }
void OnBuoyancyChanged(bool p_state) void OnBuoyancyChanged(bool p_state)
{ {
if(m_avatarReady) if(m_avatarReady)
@ -556,11 +595,21 @@ namespace ml_prm
} }
} }
} }
void OnFallDamageChanged(bool p_state) void OnFallDamageChanged(bool p_state)
{ {
m_inAir = false; m_inAir = false;
} }
void OnGestureGrabChanged(bool p_state)
{
if(m_avatarReady && m_enabled & !p_state)
{
foreach(var l_hanlder in m_ragdollBodyHandlers)
l_hanlder.Detach();
}
}
// Arbitrary // Arbitrary
public void SwitchRagdoll() public void SwitchRagdoll()
{ {
@ -644,8 +693,9 @@ namespace ml_prm
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{ {
l_handler.SetAsKinematic(true); l_handler.Detach();
l_handler.ClearFluidVolumes(); l_handler.ClearFluidVolumes();
l_handler.SetAsKinematic(true);
} }
m_lastPosition = PlayerSetup.Instance.transform.position; m_lastPosition = PlayerSetup.Instance.transform.position;

View file

@ -0,0 +1,50 @@
using ABI_RC.Core.Networking.IO.Social;
using ABI_RC.Core.Player;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace ml_prm
{
class RemoteGestureHandler : MonoBehaviour
{
internal class GestureEvent<T1, T2, T3>
{
event Action<T1, T2, T3> m_action;
public void AddHandler(Action<T1, T2, T3> p_listener) => m_action += p_listener;
public void RemoveHandler(Action<T1, T2, T3> p_listener) => m_action -= p_listener;
public void Invoke(T1 p_objA, T2 p_objB, T3 p_objC) => m_action?.Invoke(p_objA, p_objB, p_objC);
}
public static readonly GestureEvent<PuppetMaster, bool, bool> OnGestureState = new GestureEvent<PuppetMaster, bool, bool>();
PuppetMaster m_puppetMaster = null;
bool m_stateLeft = false;
bool m_stateRight = false;
void Start()
{
m_puppetMaster = this.GetComponent<PuppetMaster>();
}
void Update()
{
bool l_state = Mathf.Approximately(m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorGestureLeft, 1f);
if(m_stateLeft != l_state)
{
m_stateLeft = l_state;
if(!Settings.FriendsGrab || Friends.FriendsWith(m_puppetMaster.CVRPlayerEntity.PlayerDescriptor.ownerId))
OnGestureState.Invoke(m_puppetMaster, true, m_stateLeft);
}
l_state = Mathf.Approximately(m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorGestureRight, 1f);
if(m_stateRight != l_state)
{
m_stateRight = l_state;
if(!Settings.FriendsGrab || Friends.FriendsWith(m_puppetMaster.CVRPlayerEntity.PlayerDescriptor.ownerId))
OnGestureState.Invoke(m_puppetMaster, false, m_stateRight);
}
}
}
}

View file

@ -33,7 +33,10 @@ namespace ml_prm
JumpRecover, JumpRecover,
Buoyancy, Buoyancy,
FallDamage, FallDamage,
FallLimit FallLimit,
GestureGrab,
FriendsGrab,
GrabDistance
} }
public static bool Hotkey { get; private set; } = true; public static bool Hotkey { get; private set; } = true;
@ -54,6 +57,9 @@ namespace ml_prm
public static bool Buoyancy { get; private set; } = true; public static bool Buoyancy { get; private set; } = true;
public static bool FallDamage { get; private set; } = true; public static bool FallDamage { get; private set; } = true;
public static float FallLimit { get; private set; } = 9.899494f; public static float FallLimit { get; private set; } = 9.899494f;
public static bool GestureGrab { get; private set; } = false;
public static bool FriendsGrab { get; private set; } = true;
public static float GrabDistance { get; private set; } = 0.1f;
public static readonly SettingEvent<bool> OnHotkeyChanged = new SettingEvent<bool>(); public static readonly SettingEvent<bool> OnHotkeyChanged = new SettingEvent<bool>();
public static readonly SettingEvent<KeyCode> OnHotkeyKeyChanged = new SettingEvent<KeyCode>(); public static readonly SettingEvent<KeyCode> OnHotkeyKeyChanged = new SettingEvent<KeyCode>();
@ -73,6 +79,9 @@ namespace ml_prm
public static readonly SettingEvent<bool> OnBuoyancyChanged = new SettingEvent<bool>(); public static readonly SettingEvent<bool> OnBuoyancyChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnFallDamageChanged = new SettingEvent<bool>(); public static readonly SettingEvent<bool> OnFallDamageChanged = new SettingEvent<bool>();
public static readonly SettingEvent<float> OnFallLimitChanged = new SettingEvent<float>(); public static readonly SettingEvent<float> OnFallLimitChanged = new SettingEvent<float>();
public static readonly SettingEvent<bool> OnGestureGrabChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnFriendsGrabChanged = new SettingEvent<bool>();
public static readonly SettingEvent<float> OnGrabDistanceChanged = new SettingEvent<float>();
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;
@ -101,6 +110,9 @@ namespace ml_prm
ms_category.CreateEntry(ModSetting.Buoyancy.ToString(), Buoyancy, null, null, true), ms_category.CreateEntry(ModSetting.Buoyancy.ToString(), Buoyancy, null, null, true),
ms_category.CreateEntry(ModSetting.FallDamage.ToString(), FallDamage, null, null, true), ms_category.CreateEntry(ModSetting.FallDamage.ToString(), FallDamage, null, null, true),
ms_category.CreateEntry(ModSetting.FallLimit.ToString(), FallLimit, null, null, true), ms_category.CreateEntry(ModSetting.FallLimit.ToString(), FallLimit, null, null, true),
ms_category.CreateEntry(ModSetting.GestureGrab.ToString(), GestureGrab, null, null, true),
ms_category.CreateEntry(ModSetting.FriendsGrab.ToString(), FriendsGrab, null, null, true),
ms_category.CreateEntry(ModSetting.GrabDistance.ToString(), GrabDistance, null, null, true),
}; };
ms_entries[(int)ModSetting.HotkeyKey].OnEntryValueChangedUntyped.Subscribe(OnMelonSettingSave_HotkeyKey); ms_entries[(int)ModSetting.HotkeyKey].OnEntryValueChangedUntyped.Subscribe(OnMelonSettingSave_HotkeyKey);
@ -123,6 +135,9 @@ namespace ml_prm
Buoyancy = (bool)ms_entries[(int)ModSetting.Buoyancy].BoxedValue; Buoyancy = (bool)ms_entries[(int)ModSetting.Buoyancy].BoxedValue;
FallDamage = (bool)ms_entries[(int)ModSetting.FallDamage].BoxedValue; FallDamage = (bool)ms_entries[(int)ModSetting.FallDamage].BoxedValue;
FallLimit = Mathf.Clamp((float)ms_entries[(int)ModSetting.FallLimit].BoxedValue, 4.5f, 44.5f); FallLimit = Mathf.Clamp((float)ms_entries[(int)ModSetting.FallLimit].BoxedValue, 4.5f, 44.5f);
GestureGrab = (bool)ms_entries[(int)ModSetting.GestureGrab].BoxedValue;
FriendsGrab = (bool)ms_entries[(int)ModSetting.FriendsGrab].BoxedValue;
GrabDistance = Mathf.Clamp01((float)ms_entries[(int)ModSetting.GrabDistance].BoxedValue);
} }
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue) static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)
@ -232,6 +247,20 @@ namespace ml_prm
} }
break; break;
case ModSetting.GestureGrab:
{
GestureGrab = (bool)p_value;
OnGestureGrabChanged.Invoke(GestureGrab);
}
break;
case ModSetting.FriendsGrab:
{
FriendsGrab = (bool)p_value;
OnFriendsGrabChanged.Invoke(FriendsGrab);
}
break;
// Floats // Floats
case ModSetting.VelocityMultiplier: case ModSetting.VelocityMultiplier:
{ {
@ -267,6 +296,13 @@ namespace ml_prm
OnFallLimitChanged.Invoke(FallLimit); OnFallLimitChanged.Invoke(FallLimit);
} }
break; break;
case ModSetting.GrabDistance:
{
GrabDistance = (float)p_value;
OnGrabDistanceChanged.Invoke(GrabDistance);
}
break;
} }
if(ms_entries != null) if(ms_entries != null)

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<PackageId>PlayerRagdollMod</PackageId> <PackageId>PlayerRagdollMod</PackageId>
<Version>1.1.8</Version> <Version>1.1.9</Version>
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>None</Company> <Company>None</Company>
<Product>PlayerRagdollMod</Product> <Product>PlayerRagdollMod</Product>