Instance set changes

Additional animator parameters
Reworked rigidbodies
Update to latest LeapC and LeapCSharp
This commit is contained in:
SDraw 2024-07-20 11:13:51 +03:00
parent 1f0b518761
commit 075ff67304
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
38 changed files with 8310 additions and 8646 deletions

View file

@ -3,14 +3,14 @@ Merged set of MelonLoader mods for ChilloutVR.
**Table for game build 2023r175:** **Table for game build 2023r175:**
| Full name | Short name | Latest version | | Full name | Short name | Latest version |
|:---------:|:----------:|:--------------:| |:---------:|:----------:|:--------------:|
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.4.0 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| | [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.4.1 [:arrow_down:](../../releases/latest/download/ml_amt.dll)|
| [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_asl.dll)| | [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_asl.dll)|
| [Better Fingers Tracking](/ml_bft/README.md) | ml_bft | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_bft.dll)| | [Better Fingers Tracking](/ml_bft/README.md) | ml_bft | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_bft.dll)|
| [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.4 [:arrow_down:](../../releases/latest/download/ml_dht.dll)| | [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.5 [:arrow_down:](../../releases/latest/download/ml_dht.dll)|
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.5.1 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| | [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.5.2 [:arrow_down:](../../releases/latest/download/ml_lme.dll)|
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.1.3 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| | [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.1.4 [:arrow_down:](../../releases/latest/download/ml_pam.dll)|
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| | [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)|
| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.7 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| | [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.8 [:arrow_down:](../../releases/latest/download/ml_prm.dll)|
| [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.7 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)| | [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.7 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)|
| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| | [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_vei.dll)|

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.4.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.4.1", "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

@ -36,9 +36,12 @@ namespace ml_amt
public static void SetAvatarTPose() public static void SetAvatarTPose()
{ {
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose); if(PlayerSetup.Instance._animator.isHuman)
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; {
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
}
} }
// Engine extensions // Engine extensions

View file

@ -6,7 +6,7 @@
<Company>None</Company> <Company>None</Company>
<Product>AvatarMotionTweaker</Product> <Product>AvatarMotionTweaker</Product>
<PackageId>AvatarMotionTweaker</PackageId> <PackageId>AvatarMotionTweaker</PackageId>
<Version>1.4.0</Version> <Version>1.4.1</Version>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<AssemblyName>ml_amt</AssemblyName> <AssemblyName>ml_amt</AssemblyName>
</PropertyGroup> </PropertyGroup>

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.5", "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

@ -19,9 +19,12 @@ namespace ml_dht
public static void SetAvatarTPose() public static void SetAvatarTPose()
{ {
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose); if(PlayerSetup.Instance._animator.isHuman)
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; {
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
}
} }
} }
} }

View file

@ -6,7 +6,7 @@
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>None</Company> <Company>None</Company>
<Product>DesktopHeadTracking</Product> <Product>DesktopHeadTracking</Product>
<Version>1.2.4</Version> <Version>1.2.5</Version>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
</PropertyGroup> </PropertyGroup>

View file

@ -19,16 +19,22 @@ namespace ml_lme
void Awake() void Awake()
{ {
if(Instance == null) if((Instance != null) && (Instance != this))
Instance = this; {
Object.DestroyImmediate(this);
ScriptableObject.CreateInstance<Leap.Unity.UltraleapSettings>().ResetToDefaults(); return;
}
m_leapController = new Leap.Controller();
m_leapData = new LeapParser.LeapData();
Instance = this;
DontDestroyOnLoad(this); DontDestroyOnLoad(this);
ScriptableObject.CreateInstance<Leap.Unity.UltraleapSettings>().ResetToDefaults();
m_leapController = new Leap.Controller();
m_leapData = new LeapParser.LeapData();
}
void Start()
{
m_leapController.Device += this.OnLeapDeviceInitialized; m_leapController.Device += this.OnLeapDeviceInitialized;
m_leapController.DeviceFailure += this.OnLeapDeviceFailure; m_leapController.DeviceFailure += this.OnLeapDeviceFailure;
m_leapController.DeviceLost += this.OnLeapDeviceLost; m_leapController.DeviceLost += this.OnLeapDeviceLost;

View file

@ -26,9 +26,13 @@ namespace ml_lme
void Start() void Start()
{ {
if(Instance == null) if((Instance != null) && (Instance != this))
Instance = this; {
Object.DestroyImmediate(this);
return;
}
Instance = this;
m_inVR = Utils.IsInVR(); m_inVR = Utils.IsInVR();
m_leapElbowLeft = new GameObject("LeapElbowLeft").transform; m_leapElbowLeft = new GameObject("LeapElbowLeft").transform;

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.5.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.5.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")] [assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<PackageId>LeapMotionExtension</PackageId> <PackageId>LeapMotionExtension</PackageId>
<Version>1.5.1</Version> <Version>1.5.2</Version>
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>None</Company> <Company>None</Company>
<Product>LeapMotionExtension</Product> <Product>LeapMotionExtension</Product>

View file

@ -13,6 +13,7 @@ namespace LeapInternal
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using UnityEngine;
public class Connection public class Connection
{ {
@ -1195,11 +1196,7 @@ namespace LeapInternal
return new UnityEngine.Vector3(ray.x, ray.y, ray.z); return new UnityEngine.Vector3(ray.x, ray.y, ray.z);
} }
/// <summary> [Obsolete("calibType is not necessary. Please use the alternative PixelToRectilinearEx method.")]
/// Converts from image-space pixel coordinates to camera-space rectilinear coordinates
///
/// Also allows specifying a specific device handle and calibration type.
/// </summary>
public UnityEngine.Vector3 PixelToRectilinearEx(IntPtr deviceHandle, public UnityEngine.Vector3 PixelToRectilinearEx(IntPtr deviceHandle,
Image.CameraType camera, Image.CalibrationType calibType, UnityEngine.Vector3 pixel) Image.CameraType camera, Image.CalibrationType calibType, UnityEngine.Vector3 pixel)
{ {
@ -1216,6 +1213,24 @@ namespace LeapInternal
return new UnityEngine.Vector3(ray.x, ray.y, ray.z); return new UnityEngine.Vector3(ray.x, ray.y, ray.z);
} }
/// <summary>
/// Converts from image-space pixel coordinates to camera-space rectilinear coordinates
///
/// Also allows specifying a specific device handle and calibration type.
/// </summary>
public UnityEngine.Vector3 PixelToRectilinearEx(IntPtr deviceHandle,
Image.CameraType camera, UnityEngine.Vector3 pixel)
{
LEAP_VECTOR pixelStruct = new LEAP_VECTOR(pixel);
LEAP_VECTOR ray = LeapC.LeapPixelToRectilinearEx(_leapConnection,
deviceHandle,
(camera == Image.CameraType.LEFT ?
eLeapPerspectiveType.eLeapPerspectiveType_stereo_left :
eLeapPerspectiveType.eLeapPerspectiveType_stereo_right),
pixelStruct);
return new UnityEngine.Vector3(ray.x, ray.y, ray.z);
}
/// <summary> /// <summary>
/// Converts from camera-space rectilinear coordinates to image-space pixel coordinates /// Converts from camera-space rectilinear coordinates to image-space pixel coordinates
/// </summary> /// </summary>
@ -1302,6 +1317,48 @@ namespace LeapInternal
Marshal.FreeHGlobal(buffer); Marshal.FreeHGlobal(buffer);
} }
/// <summary>
/// Request the Extrinsic Camera Matrix
/// </summary>
public Matrix4x4 LeapExtrinsicCameraMatrix(Image.CameraType camera, Device device)
{
float[] data = new float[16];
try
{
eLeapRS result = eLeapRS.eLeapRS_Success;
if (device != null)
{
result = LeapC.LeapExtrinsicCameraMatrixEx(_leapConnection, device.Handle, camera == Image.CameraType.LEFT ?
eLeapPerspectiveType.eLeapPerspectiveType_stereo_left :
eLeapPerspectiveType.eLeapPerspectiveType_stereo_right, data);
}
else
{
result = LeapC.LeapExtrinsicCameraMatrix(_leapConnection, camera == Image.CameraType.LEFT ?
eLeapPerspectiveType.eLeapPerspectiveType_stereo_left :
eLeapPerspectiveType.eLeapPerspectiveType_stereo_right, data);
}
if (result != eLeapRS.eLeapRS_Success)
{
return new Matrix4x4(new Vector4(data[0], data[1], data[2], data[3]),
new Vector4(data[4], data[5], data[6], data[7]),
new Vector4(data[8], data[9], data[10], data[11]),
new Vector4(data[12], data[13], data[14], data[15])
);
}
}
catch (Exception e)
{
Debug.LogException(e);
}
return Matrix4x4.identity;
}
/// <summary> /// <summary>
/// Send a specific set of hints to hDevice, if this does not include previously set ones, they will be cleared. /// Send a specific set of hints to hDevice, if this does not include previously set ones, they will be cleared.
/// </summary> /// </summary>

View file

@ -863,6 +863,26 @@ namespace Leap
_connection.GetInterpolatedFrameFromTime(toFill, time, sourceTime, device); _connection.GetInterpolatedFrameFromTime(toFill, time, sourceTime, device);
} }
public UnityEngine.Matrix4x4 LeapExtrinsicCameraMatrix(Image.CameraType camera, Device device)
{
return _connection.LeapExtrinsicCameraMatrix(camera, device);
}
public UnityEngine.Vector3 RectilinearToPixel(Image.CameraType camera, UnityEngine.Vector3 ray)
{
return _connection.RectilinearToPixel(camera, ray);
}
public UnityEngine.Vector3 RectilinearToPixelEx(Image.CameraType camera, UnityEngine.Vector3 ray, Device device)
{
return _connection.RectilinearToPixelEx(device.Handle, camera, ray);
}
public UnityEngine.Vector3 PixelToRectilinearEx(Image.CameraType camera, UnityEngine.Vector3 pixel, Device device)
{
return _connection.PixelToRectilinearEx(device.Handle, camera, pixel);
}
/// <summary> /// <summary>
/// Returns a timestamp value as close as possible to the current time. /// Returns a timestamp value as close as possible to the current time.
/// Values are in microseconds, as with all the other timestamp values. /// Values are in microseconds, as with all the other timestamp values.

View file

@ -14,9 +14,6 @@ namespace LeapInternal
{ {
public static readonly float MM_TO_M = 1e-3f; public static readonly float MM_TO_M = 1e-3f;
public static bool leapToUnityTransformSet = false;
private static LeapTransform leapToUnityTransform;
/** /**
* Provides a static LeapTransform that converts from Leap units and coordinates to Unity * Provides a static LeapTransform that converts from Leap units and coordinates to Unity
*/ */
@ -24,12 +21,8 @@ namespace LeapInternal
{ {
get get
{ {
if (!leapToUnityTransformSet) LeapTransform leapToUnityTransform = new LeapTransform(Vector3.zero, Quaternion.identity, new Vector3(MM_TO_M, MM_TO_M, MM_TO_M));
{ leapToUnityTransform.MirrorZ();
leapToUnityTransform = new LeapTransform(Vector3.zero, Quaternion.identity, new Vector3(MM_TO_M, MM_TO_M, MM_TO_M));
leapToUnityTransform.MirrorZ();
leapToUnityTransformSet = true;
}
return leapToUnityTransform; return leapToUnityTransform;
} }

View file

@ -1133,10 +1133,14 @@ namespace LeapInternal
public static extern LEAP_VECTOR LeapPixelToRectilinear(IntPtr hConnection, public static extern LEAP_VECTOR LeapPixelToRectilinear(IntPtr hConnection,
eLeapPerspectiveType camera, LEAP_VECTOR pixel); eLeapPerspectiveType camera, LEAP_VECTOR pixel);
[DllImport("LeapC", EntryPoint = "LeapPixelToRectilinearEx")] [Obsolete("Use of calibrationType is not valid. Use alternative LeapPixelToRectilinearEx method."), DllImport("LeapC", EntryPoint = "LeapPixelToRectilinearEx")]
public static extern LEAP_VECTOR LeapPixelToRectilinearEx(IntPtr hConnection, public static extern LEAP_VECTOR LeapPixelToRectilinearEx(IntPtr hConnection,
IntPtr hDevice, eLeapPerspectiveType camera, eLeapCameraCalibrationType calibrationType, LEAP_VECTOR pixel); IntPtr hDevice, eLeapPerspectiveType camera, eLeapCameraCalibrationType calibrationType, LEAP_VECTOR pixel);
[DllImport("LeapC", EntryPoint = "LeapPixelToRectilinearEx")]
public static extern LEAP_VECTOR LeapPixelToRectilinearEx(IntPtr hConnection,
IntPtr hDevice, eLeapPerspectiveType camera, LEAP_VECTOR pixel);
[DllImport("LeapC", EntryPoint = "LeapRectilinearToPixel")] [DllImport("LeapC", EntryPoint = "LeapRectilinearToPixel")]
public static extern LEAP_VECTOR LeapRectilinearToPixel(IntPtr hConnection, public static extern LEAP_VECTOR LeapRectilinearToPixel(IntPtr hConnection,
eLeapPerspectiveType camera, LEAP_VECTOR rectilinear); eLeapPerspectiveType camera, LEAP_VECTOR rectilinear);
@ -1145,6 +1149,14 @@ namespace LeapInternal
public static extern LEAP_VECTOR LeapRectilinearToPixelEx(IntPtr hConnection, public static extern LEAP_VECTOR LeapRectilinearToPixelEx(IntPtr hConnection,
IntPtr hDevice, eLeapPerspectiveType camera, LEAP_VECTOR rectilinear); IntPtr hDevice, eLeapPerspectiveType camera, LEAP_VECTOR rectilinear);
[DllImport("LeapC", EntryPoint = "LeapExtrinsicCameraMatrix")]
public static extern eLeapRS LeapExtrinsicCameraMatrix(IntPtr hConnection, eLeapPerspectiveType camera,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] float[] extrinsicMatrix);
[DllImport("LeapC", EntryPoint = "LeapExtrinsicCameraMatrixEx")]
public static extern eLeapRS LeapExtrinsicCameraMatrixEx(IntPtr hConnection, IntPtr hDevice, eLeapPerspectiveType camera,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] float[] extrinsicMatrix);
[DllImport("LeapC", EntryPoint = "LeapCloseDevice")] [DllImport("LeapC", EntryPoint = "LeapCloseDevice")]
public static extern void CloseDevice(IntPtr pDevice); public static extern void CloseDevice(IntPtr pDevice);
@ -1273,7 +1285,6 @@ namespace LeapInternal
[DllImport("LeapC", EntryPoint = "LeapGetVersion")] [DllImport("LeapC", EntryPoint = "LeapGetVersion")]
public static extern eLeapRS GetVersion(IntPtr hConnection, eLeapVersionPart versionPart, ref LEAP_VERSION pVersion); public static extern eLeapRS GetVersion(IntPtr hConnection, eLeapVersionPart versionPart, ref LEAP_VERSION pVersion);
[DllImport("LeapC", EntryPoint = "LeapGetServerStatus")] [DllImport("LeapC", EntryPoint = "LeapGetServerStatus")]
public static extern eLeapRS GetServerStatus(UInt32 timeout, ref IntPtr status); public static extern eLeapRS GetServerStatus(UInt32 timeout, ref IntPtr status);

View file

@ -25,12 +25,16 @@ namespace LeapInternal
if (lastRequestTimestamp + requestInterval < Time.realtimeSinceStartup) if (lastRequestTimestamp + requestInterval < Time.realtimeSinceStartup)
{ {
IntPtr statusPtr = new IntPtr(); IntPtr statusPtr = new IntPtr();
LeapC.GetServerStatus(1000, ref statusPtr); LeapC.GetServerStatus(500, ref statusPtr);
lastStatus = Marshal.PtrToStructure<LeapC.LEAP_SERVER_STATUS>(statusPtr); if (statusPtr != IntPtr.Zero)
{
lastStatus = Marshal.PtrToStructure<LeapC.LEAP_SERVER_STATUS>(statusPtr);
MarshalUnmananagedArray2Struct(lastStatus.devices, (int)lastStatus.device_count, out lastDevices);
LeapC.ReleaseServerStatus(ref lastStatus);
}
MarshalUnmananagedArray2Struct(lastStatus.devices, (int)lastStatus.device_count, out lastDevices);
LeapC.ReleaseServerStatus(ref lastStatus);
lastRequestTimestamp = Time.realtimeSinceStartup; lastRequestTimestamp = Time.realtimeSinceStartup;
} }
} }
@ -97,7 +101,7 @@ namespace LeapInternal
return ""; return "";
} }
public static void MarshalUnmananagedArray2Struct<T>(IntPtr unmanagedArray, int length, out T[] mangagedArray) static void MarshalUnmananagedArray2Struct<T>(IntPtr unmanagedArray, int length, out T[] mangagedArray)
{ {
var size = Marshal.SizeOf(typeof(T)); var size = Marshal.SizeOf(typeof(T));
mangagedArray = new T[length]; mangagedArray = new T[length];

View file

@ -1,482 +1,482 @@
ULTRALEAP TRACKING SDK AGREEMENT ULTRALEAP TRACKING SDK AGREEMENT
Updated: 22 March 2022 Updated: 22 March 2022
Permitted uses Permitted uses
This SDK Agreement (“Agreement”) covers use of the Ultraleap hand tracking SDK (the “SDK”) by This SDK Agreement (“Agreement”) covers use of the Ultraleap hand tracking SDK (the “SDK”) by
individuals and businesses for the following purposes: individuals and businesses for the following purposes:
1. Your personal, non-commercial use (for the avoidance of doubt, excluding use for the design or 1. Your personal, non-commercial use (for the avoidance of doubt, excluding use for the design or
manufacture of a commercial or distributable product (e.g in design studios)); or manufacture of a commercial or distributable product (e.g in design studios)); or
2. Commercial use for the development and sale consumer facing games, made available for sale to 2. Commercial use for the development and sale consumer facing games, made available for sale to
be purchased by consumers for personal use either at retail or through app stores (excluding, be purchased by consumers for personal use either at retail or through app stores (excluding,
without limitation, location-based entertainment and arcade applications); or without limitation, location-based entertainment and arcade applications); or
3. Demonstration of your application to internal and external stakeholders and customers where 3. Demonstration of your application to internal and external stakeholders and customers where
there is no transaction, no sale of tickets specifically for the application, or any other form of there is no transaction, no sale of tickets specifically for the application, or any other form of
compensation for you or your organisation, compensation for you or your organisation,
but in all cases excluding applications relating to the following: (a) the production of or trade in tobacco, but in all cases excluding applications relating to the following: (a) the production of or trade in tobacco,
alcoholic beverages, and related products, (b) the production or trade in weapons of any kind or any alcoholic beverages, and related products, (b) the production or trade in weapons of any kind or any
military applications, (c) casinos, gambling and equivalent enterprises, (d) human cloning, human military applications, (c) casinos, gambling and equivalent enterprises, (d) human cloning, human
embryos, or stem cells, or (e) nuclear energy. embryos, or stem cells, or (e) nuclear energy.
Any other uses, or applications using third party hardware are “Specialised Applications” and will require Any other uses, or applications using third party hardware are “Specialised Applications” and will require
a separate license agreement. Please contact Ultraleap info@ultraleap.com for more information. a separate license agreement. Please contact Ultraleap info@ultraleap.com for more information.
In each case, the SDK may only be used with Ultraleap Hardware and Ultraleap Software. In each case, the SDK may only be used with Ultraleap Hardware and Ultraleap Software.
1. Parties 1. Parties
1.1. This Agreement is made between the individual or entity (“you” or the “Developer”) that accepts 1.1. This Agreement is made between the individual or entity (“you” or the “Developer”) that accepts
it and Ultraleap Limited (“Ultraleap”). You accept this Agreement by (a) accepting it on download it and Ultraleap Limited (“Ultraleap”). You accept this Agreement by (a) accepting it on download
of the SDK, or (b) if you use or access the SDK or any part of the SDK. Your entry into this of the SDK, or (b) if you use or access the SDK or any part of the SDK. Your entry into this
Agreement also binds your authorized users, and your company or organisation. Agreement also binds your authorized users, and your company or organisation.
1.2. If you do not agree to the terms of this Agreement you must not use the SDK. 1.2. If you do not agree to the terms of this Agreement you must not use the SDK.
1.3. Capitalized terms bear the meanings given in the “Definitions” section of this Agreement. 1.3. Capitalized terms bear the meanings given in the “Definitions” section of this Agreement.
1.4. This Agreement incorporates the terms of the Ultraleap Hand Tracking End User License 1.4. This Agreement incorporates the terms of the Ultraleap Hand Tracking End User License
Agreement (“EULA”), which is available at https://developer.leapmotion.com/end-user-license- Agreement (“EULA”), which is available at https://developer.leapmotion.com/end-user-license-
agreement or from Ultraleap on request. In the event of a conflict between these terms and the agreement or from Ultraleap on request. In the event of a conflict between these terms and the
EULA, these terms will prevail. EULA, these terms will prevail.
2. License 2. License
Development License Development License
2.1. Conditional on your compliance with the terms and conditions of this Agreement, Ultraleap 2.1. Conditional on your compliance with the terms and conditions of this Agreement, Ultraleap
hereby grants you a limited, non-exclusive, personal, revocable, non-sublicensable, and non- hereby grants you a limited, non-exclusive, personal, revocable, non-sublicensable, and non-
transferable license to: transferable license to:
2.1.1. install and use a reasonable number of copies of the SDK on computers owned or 2.1.1. install and use a reasonable number of copies of the SDK on computers owned or
controlled by you for the purpose of developing and testing applications that (a) are not controlled by you for the purpose of developing and testing applications that (a) are not
Specialised Applications and (b) are intended for use solely in connection with Ultraleap Specialised Applications and (b) are intended for use solely in connection with Ultraleap
Hardware and Ultraleap Software (each being an “Ultraleap Enabled Application”); and Hardware and Ultraleap Software (each being an “Ultraleap Enabled Application”); and
2.1.2. modify and incorporate into your Ultraleap Enabled Application any sample code 2.1.2. modify and incorporate into your Ultraleap Enabled Application any sample code
provided in the SDK. provided in the SDK.
Distribution License Distribution License
2.2. Conditional on your compliance with the terms and conditions of this Agreement, Ultraleap 2.2. Conditional on your compliance with the terms and conditions of this Agreement, Ultraleap
hereby grants you a limited, non-exclusive, personal, revocable, non-transferrable license of hereby grants you a limited, non-exclusive, personal, revocable, non-transferrable license of
Ultraleaps intellectual property rights to the extent necessary to: Ultraleaps intellectual property rights to the extent necessary to:
2.2.1. copy and distribute (or have copied and distributed) the Ultraleap Redistributables, 2.2.1. copy and distribute (or have copied and distributed) the Ultraleap Redistributables,
solely as compiled with, incorporated into, or packaged with, your Ultraleap Enabled solely as compiled with, incorporated into, or packaged with, your Ultraleap Enabled
Application; and Application; and
2.2.2. to make (but not have made), use, sell, offer for sale, and import your Ultraleap Enabled 2.2.2. to make (but not have made), use, sell, offer for sale, and import your Ultraleap Enabled
Application. Application.
3. Restrictions 3. Restrictions
3.1. The license granted to you in section 2.1 and section 2.2 is subject to the following restrictions, 3.1. The license granted to you in section 2.1 and section 2.2 is subject to the following restrictions,
as well as others listed in this Agreement: as well as others listed in this Agreement:
3.1.1. Except as expressly permitted in section 2.1, (a) you may not publish, distribute, or copy 3.1.1. Except as expressly permitted in section 2.1, (a) you may not publish, distribute, or copy
the SDK, and (b) you may not modify or create derivative works of the SDK; the SDK, and (b) you may not modify or create derivative works of the SDK;
3.1.2. Except as expressly permitted in section 2.2, you may not, and may not allow any third 3.1.2. Except as expressly permitted in section 2.2, you may not, and may not allow any third
party, directly or indirectly, to publish, post, or otherwise make available, the Ultraleap party, directly or indirectly, to publish, post, or otherwise make available, the Ultraleap
Redistributables; Redistributables;
3.1.3. You may not, and may not enable others to, distributed the Non-Redistributable 3.1.3. You may not, and may not enable others to, distributed the Non-Redistributable
Materials; Materials;
3.1.4. You may use the SDK solely in connection with Ultraleap Hardware and/or Ultraleap 3.1.4. You may use the SDK solely in connection with Ultraleap Hardware and/or Ultraleap
Software; Software;
3.1.5. You may not use the SDK to create, or aid in the creation, directly or indirectly, of any 3.1.5. You may not use the SDK to create, or aid in the creation, directly or indirectly, of any
software or hardware which provides hand tracking functionality or which is otherwise software or hardware which provides hand tracking functionality or which is otherwise
substantially similar to the features or functionality of Ultraleap products; substantially similar to the features or functionality of Ultraleap products;
3.1.6. You may not, and may not enable others to, directly or indirectly, reverse engineer, 3.1.6. You may not, and may not enable others to, directly or indirectly, reverse engineer,
decompile, disassemble, or otherwise attempt to reconstruct, identify, or discover any decompile, disassemble, or otherwise attempt to reconstruct, identify, or discover any
source code, underlying ideas, techniques, or algorithms in the Ultraleap Software, the source code, underlying ideas, techniques, or algorithms in the Ultraleap Software, the
Ultraleap Hardware, or any software which forms part of the SDK, nor attempt to Ultraleap Hardware, or any software which forms part of the SDK, nor attempt to
circumvent any related security measures (except as and only to the extent any circumvent any related security measures (except as and only to the extent any
foregoing restriction is prohibited by applicable law notwithstanding the foregoing foregoing restriction is prohibited by applicable law notwithstanding the foregoing
restriction, or to the extent as may be permitted by licensing terms governing the use of restriction, or to the extent as may be permitted by licensing terms governing the use of
any open source software components or sample code contained within the SDK; any open source software components or sample code contained within the SDK;
3.1.7. You may not remove, obscure, or alter any proprietary rights or confidentiality notices 3.1.7. You may not remove, obscure, or alter any proprietary rights or confidentiality notices
within the SDK or any software, documentation, or other materials in it or supplied with within the SDK or any software, documentation, or other materials in it or supplied with
it; it;
3.1.8. You must not allow the Ultraleap Software or SDK to fall under the terms of any license 3.1.8. You must not allow the Ultraleap Software or SDK to fall under the terms of any license
which would obligate you or Ultraleap to make available or publish any part of the which would obligate you or Ultraleap to make available or publish any part of the
Ultraleap Software or SDK. Ultraleap Software or SDK.
3.1.9. You may not create Ultraleap Enabled Applications or other software that prevent or 3.1.9. You may not create Ultraleap Enabled Applications or other software that prevent or
degrade the interaction of applications developed by others with the Ultraleap Software; degrade the interaction of applications developed by others with the Ultraleap Software;
3.1.10. You may not represent functionality provided by any Ultraleap hardware or software as 3.1.10. You may not represent functionality provided by any Ultraleap hardware or software as
your technology or the technology of any third party. For example (without limitation) your technology or the technology of any third party. For example (without limitation)
you may not describe any application, technology, or feature developed or distributed you may not describe any application, technology, or feature developed or distributed
by you that incorporates Ultraleap technology as your gesture or touchless control by you that incorporates Ultraleap technology as your gesture or touchless control
technology without providing attribution to Ultraleap; and technology without providing attribution to Ultraleap; and
3.1.11. You may not allow your Ultraleap Enabled Application to be used for a High Risk Use. 3.1.11. You may not allow your Ultraleap Enabled Application to be used for a High Risk Use.
4. Updates 4. Updates
4.1. The terms of this Agreement will apply to any Updates which Ultraleap (in its sole discretion) 4.1. The terms of this Agreement will apply to any Updates which Ultraleap (in its sole discretion)
makes available to you. You agree that Updates may require you to change or update your makes available to you. You agree that Updates may require you to change or update your
Ultraleap Enabled Application, and may affect your ability to use, access, or interact with the Ultraleap Enabled Application, and may affect your ability to use, access, or interact with the
Ultraleap Software, the Ultraleap Hardware, and/or the SDK. You are solely responsible for Ultraleap Software, the Ultraleap Hardware, and/or the SDK. You are solely responsible for
turning off any auto-update functionality of the Ultraleap Software. turning off any auto-update functionality of the Ultraleap Software.
5. Trademarks and Marketing 5. Trademarks and Marketing
5.1. Conditioned upon compliance with the terms and conditions of this Agreement, Ultraleap grants 5.1. Conditioned upon compliance with the terms and conditions of this Agreement, Ultraleap grants
you a limited, non-exclusive, personal, license to reproduce and use Ultraleap trademarks solely you a limited, non-exclusive, personal, license to reproduce and use Ultraleap trademarks solely
to (a) mark the Ultraleap Enabled Application, (b) produce and make available related collateral, to (a) mark the Ultraleap Enabled Application, (b) produce and make available related collateral,
and (c) to promote and market your Ultraleap Enabled Application, in each case solely in and (c) to promote and market your Ultraleap Enabled Application, in each case solely in
accordance with the Ultraleap trademark guidelines that Ultraleap may provide to you from time accordance with the Ultraleap trademark guidelines that Ultraleap may provide to you from time
to time. to time.
5.2. For so long as Ultraleap technology is included with the Ultraleap Enabled Application, you must 5.2. For so long as Ultraleap technology is included with the Ultraleap Enabled Application, you must
identify on the packaging of the Ultraleap Enabled Application, the loading screen and start-up identify on the packaging of the Ultraleap Enabled Application, the loading screen and start-up
messages for the Ultraleap Enabled Application, and list on your website and marketing collateral messages for the Ultraleap Enabled Application, and list on your website and marketing collateral
(in each case, where applicable), as prominently as other listed features and functionality, that (in each case, where applicable), as prominently as other listed features and functionality, that
Ultraleap technology is included with the Ultraleap Enabled Application, in accordance with the Ultraleap technology is included with the Ultraleap Enabled Application, in accordance with the
Ultraleap trademark guidelines that Ultraleap may provide to you from time to time. All Ultraleap trademark guidelines that Ultraleap may provide to you from time to time. All
references to Ultraleap or Ultraleap Technology will be subject to Ultraleaps prior approval, references to Ultraleap or Ultraleap Technology will be subject to Ultraleaps prior approval,
which will not be unreasonably withheld. which will not be unreasonably withheld.
5.3. Ultraleap may at its option mention you and your products using Ultraleap technology in 5.3. Ultraleap may at its option mention you and your products using Ultraleap technology in
Ultraleaps press releases, press briefings, social media accounts, and/or website, and may use Ultraleaps press releases, press briefings, social media accounts, and/or website, and may use
your trademarks for such purpose. You grant to Ultraleap and its affiliates a non-exclusive, your trademarks for such purpose. You grant to Ultraleap and its affiliates a non-exclusive,
worldwide and royalty-free limited license to use, reproduce, display, perform, publish and worldwide and royalty-free limited license to use, reproduce, display, perform, publish and
distribute screenshots, elements, assets, photographic, graphic or video reproductions or distribute screenshots, elements, assets, photographic, graphic or video reproductions or
fragments of your Ultraleap Enabled Application in any medium or media, solely for purposes of fragments of your Ultraleap Enabled Application in any medium or media, solely for purposes of
promotion of your Ultraleap Enabled Application or of Ultraleap and its technology and business. promotion of your Ultraleap Enabled Application or of Ultraleap and its technology and business.
The rights set out in this section 5.3 will survive termination of this Agreement in respect of The rights set out in this section 5.3 will survive termination of this Agreement in respect of
materials already in existence as at the date of termination. materials already in existence as at the date of termination.
6. EULA and Other Licenses 6. EULA and Other Licenses
6.1. Example code made publicly available by Ultraleap on its developer web site may be provided 6.1. Example code made publicly available by Ultraleap on its developer web site may be provided
subject to the Apache 2.0 license, this Agreement, or other licenses, as specified in the notice or subject to the Apache 2.0 license, this Agreement, or other licenses, as specified in the notice or
readme files distributed with the example or in related documentation. The SDK may otherwise readme files distributed with the example or in related documentation. The SDK may otherwise
include software or other materials that are provided under a separate license agreement, and include software or other materials that are provided under a separate license agreement, and
that separate license will govern the use of such software or other materials in the event of a that separate license will govern the use of such software or other materials in the event of a
conflict with this Agreement. Any such separate license agreement may be indicated in the conflict with this Agreement. Any such separate license agreement may be indicated in the
license, notice, or readme files distributed with the applicable software or other materials or in license, notice, or readme files distributed with the applicable software or other materials or in
related documentation. related documentation.
6.2. You must either require end users of your Ultraleap Enabled Application to affirmatively agree to 6.2. You must either require end users of your Ultraleap Enabled Application to affirmatively agree to
the Ultraleap EULA, or require its End Users to affirmatively agree to your own end user license the Ultraleap EULA, or require its End Users to affirmatively agree to your own end user license
agreement that protects Ultraleap at least as much as the Ultraleap EULA. agreement that protects Ultraleap at least as much as the Ultraleap EULA.
7. High Risk Uses and Waiver 7. High Risk Uses and Waiver
7.1. Notwithstanding anything in this Agreement, you are not licensed to, and you agree not to, use, 7.1. Notwithstanding anything in this Agreement, you are not licensed to, and you agree not to, use,
copy, sell, offer for sale, or distribute the SDK, Ultraleap Hardware, Ultraleap Software or copy, sell, offer for sale, or distribute the SDK, Ultraleap Hardware, Ultraleap Software or
Ultraleap Redistributables (whether compiled with, incorporated into, or packaged with your Ultraleap Redistributables (whether compiled with, incorporated into, or packaged with your
Ultraleap Enabled Application or otherwise), for or in connection with uses where failure or fault Ultraleap Enabled Application or otherwise), for or in connection with uses where failure or fault
of the Ultraleap Hardware, Ultraleap Software, Ultraleap Redistributables or your Ultraleap of the Ultraleap Hardware, Ultraleap Software, Ultraleap Redistributables or your Ultraleap
Enabled Application could lead to death or serious bodily injury of any person, or to severe Enabled Application could lead to death or serious bodily injury of any person, or to severe
physical or environmental damage (“High Risk Use”). Any such use is strictly prohibited. physical or environmental damage (“High Risk Use”). Any such use is strictly prohibited.
7.2. You acknowledge the SDK may allow you to develop Ultraleap Enabled Applications that enable 7.2. You acknowledge the SDK may allow you to develop Ultraleap Enabled Applications that enable
the control of motorized or mechanical equipment, or other systems, machines or devices. If you the control of motorized or mechanical equipment, or other systems, machines or devices. If you
elect to use the SDK in such a way, you must take steps to design and test your Ultraleap Enabled elect to use the SDK in such a way, you must take steps to design and test your Ultraleap Enabled
Applications to ensure that your Ultraleap Enabled Applications do not present risks of personal Applications to ensure that your Ultraleap Enabled Applications do not present risks of personal
injury or death, property damage, or other losses. The Ultraleap Hardware, the Ultraleap injury or death, property damage, or other losses. The Ultraleap Hardware, the Ultraleap
Software, the Ultraleap Redistributables and other software in the SDK may not always function Software, the Ultraleap Redistributables and other software in the SDK may not always function
as intended. You must design your Ultraleap Enabled Applications so that any failure of Ultraleap as intended. You must design your Ultraleap Enabled Applications so that any failure of Ultraleap
Technology and/or such other software as Ultraleap may make available from time to time does Technology and/or such other software as Ultraleap may make available from time to time does
not cause personal injury or death, property damage, or other losses. If you choose to use the not cause personal injury or death, property damage, or other losses. If you choose to use the
SDK, (i) you assume all risk that use of the Ultraleap Technology and/or such other software by SDK, (i) you assume all risk that use of the Ultraleap Technology and/or such other software by
you or by any others causes any harm or loss, including to the end users of your Ultraleap you or by any others causes any harm or loss, including to the end users of your Ultraleap
Enabled Applications or to third parties, (ii) you hereby waive, on behalf of yourself and your Enabled Applications or to third parties, (ii) you hereby waive, on behalf of yourself and your
Authorized Users, all claims against Ultraleap and its affiliates related to such use, harm or loss Authorized Users, all claims against Ultraleap and its affiliates related to such use, harm or loss
(including, but not limited to, any claim that Ultraleap Technology or such other software is (including, but not limited to, any claim that Ultraleap Technology or such other software is
defective), and (iii) you agree to hold Ultraleap and its affiliates harmless from such claims. defective), and (iii) you agree to hold Ultraleap and its affiliates harmless from such claims.
8. Confidentiality and Data Protection 8. Confidentiality and Data Protection
8.1. Beta Software etc. Obligations. You acknowledge and agree that Ultraleap may share alpha or 8.1. Beta Software etc. Obligations. You acknowledge and agree that Ultraleap may share alpha or
beta software or hardware with you that it identifies as non-public. If so, you agree not to beta software or hardware with you that it identifies as non-public. If so, you agree not to
disclose such software or hardware to others without the prior written consent of Ultraleap disclose such software or hardware to others without the prior written consent of Ultraleap
until the time, if any, it is made public by Ultraleap, and to use such software or hardware only until the time, if any, it is made public by Ultraleap, and to use such software or hardware only
as expressly permitted by Ultraleap. Without limitation to the foregoing, the distribution license as expressly permitted by Ultraleap. Without limitation to the foregoing, the distribution license
set out in section 2.2 shall not apply to any alpha or beta software which may be shared with set out in section 2.2 shall not apply to any alpha or beta software which may be shared with
you. you.
8.2. Your Information. Ultraleap may collect personal information provided by you or your 8.2. Your Information. Ultraleap may collect personal information provided by you or your
Authorized Users to Ultraleap or any group company of Ultraleap in connection with the SDK, Authorized Users to Ultraleap or any group company of Ultraleap in connection with the SDK,
and may collect other information from you or your Authorized Users, including technical, non- and may collect other information from you or your Authorized Users, including technical, non-
personally identifiable and/or aggregated information such as usage statistics, hardware personally identifiable and/or aggregated information such as usage statistics, hardware
configuration, problem / fault data, IP addresses, version number of the SDK, information about configuration, problem / fault data, IP addresses, version number of the SDK, information about
which tools and/or services in the SDK are being used and how they are being used, and any which tools and/or services in the SDK are being used and how they are being used, and any
other information described in Ultraleaps privacy policy, currently available at other information described in Ultraleaps privacy policy, currently available at
https://www.ultraleap.com/privacy-policy/. Ultraleap may use the information collected to https://www.ultraleap.com/privacy-policy/. Ultraleap may use the information collected to
facilitate the provision of Updates and other services to you, to verify compliance with, and facilitate the provision of Updates and other services to you, to verify compliance with, and
enforce, the terms of this Agreement, to improve the SDK and Ultraleaps other products, and enforce, the terms of this Agreement, to improve the SDK and Ultraleaps other products, and
for any other purposes set out in Ultraleaps privacy policy (these uses, collectively, are for any other purposes set out in Ultraleaps privacy policy (these uses, collectively, are
“Permitted Uses”). The information collected may be transferred to, stored, and processed in a “Permitted Uses”). The information collected may be transferred to, stored, and processed in a
destination outside the European Economic Area, including (without limitation) by our staff in destination outside the European Economic Area, including (without limitation) by our staff in
the USA, China, Japan, and Hong Kong. By submitting information about you and/or your the USA, China, Japan, and Hong Kong. By submitting information about you and/or your
Authorized Users to Ultraleap through your access and use of the SDK, you consent to Authorized Users to Ultraleap through your access and use of the SDK, you consent to
Ultraleaps collection and use of the information for the Permitted Uses and represent that you Ultraleaps collection and use of the information for the Permitted Uses and represent that you
have obtained all consents and permits necessary under applicable law to disclose your have obtained all consents and permits necessary under applicable law to disclose your
Authorized Users information to Ultraleap for the Permitted Uses. You further agree that Authorized Users information to Ultraleap for the Permitted Uses. You further agree that
Ultraleap may provide any information collected under this Section 8.2, including your or your Ultraleap may provide any information collected under this Section 8.2, including your or your
Authorized Users user name, IP address or other identifying information to law enforcement Authorized Users user name, IP address or other identifying information to law enforcement
authorities or as required by applicable law or regulation. authorities or as required by applicable law or regulation.
9. Ownership and Feedback 9. Ownership and Feedback
9.1. As between you and Ultraleap, Ultraleap owns all right, title, and interest, including all 9.1. As between you and Ultraleap, Ultraleap owns all right, title, and interest, including all
intellectual property rights, in and to the SDK, the Ultraleap Software, Ultraleap Hardware, the intellectual property rights, in and to the SDK, the Ultraleap Software, Ultraleap Hardware, the
Ultraleap Redistributables, and all documentation associated with the foregoing, other than any Ultraleap Redistributables, and all documentation associated with the foregoing, other than any
third party software or materials incorporated into the SDK. You agree not to contest Ultraleaps third party software or materials incorporated into the SDK. You agree not to contest Ultraleaps
ownership of any of the foregoing. ownership of any of the foregoing.
9.2. Subject to Section 9.1, Ultraleap agrees that it obtains no right, title, or interest from you (or 9.2. Subject to Section 9.1, Ultraleap agrees that it obtains no right, title, or interest from you (or
your licensors) under this Agreement in or to your Ultraleap Enabled Applications, including any your licensors) under this Agreement in or to your Ultraleap Enabled Applications, including any
intellectual property rights which subsist in those Ultraleap Enabled Applications. intellectual property rights which subsist in those Ultraleap Enabled Applications.
9.3. Feedback. You may (but are not required to) provide feedback, comments, and suggestions 9.3. Feedback. You may (but are not required to) provide feedback, comments, and suggestions
(collectively “Feedback”) to Ultraleap. You hereby grant to Ultraleap a non-exclusive, perpetual, (collectively “Feedback”) to Ultraleap. You hereby grant to Ultraleap a non-exclusive, perpetual,
irrevocable, paid-up, transferrable, sub-licensable, worldwide license under all intellectual irrevocable, paid-up, transferrable, sub-licensable, worldwide license under all intellectual
property rights covering such Feedback to use, disclose, and exploit all such Feedback for any property rights covering such Feedback to use, disclose, and exploit all such Feedback for any
purpose. purpose.
10. Your Obligations and Warranties 10. Your Obligations and Warranties
In addition to your other obligations under this Agreement, you warrant and agree that: In addition to your other obligations under this Agreement, you warrant and agree that:
10.1. you are at least 18 years of age and have the right and authority to enter into this Agreement on 10.1. you are at least 18 years of age and have the right and authority to enter into this Agreement on
your own behalf and that of your Authorized Users. If you are entering into this Agreement on your own behalf and that of your Authorized Users. If you are entering into this Agreement on
behalf of your company or organization, you warrant that you have the right and authority to behalf of your company or organization, you warrant that you have the right and authority to
legally bind your company or organization and its Authorized Users; legally bind your company or organization and its Authorized Users;
10.2. you will use the SDK only in accordance with all accompanying documentation, and in the 10.2. you will use the SDK only in accordance with all accompanying documentation, and in the
manner expressly permitted by this Agreement; and manner expressly permitted by this Agreement; and
10.3. your use of the SDK, and the marketing, sales and distribution of your Ultraleap Enabled 10.3. your use of the SDK, and the marketing, sales and distribution of your Ultraleap Enabled
Application, will be in compliance with all applicable laws and regulations and all UK, U.S. and Application, will be in compliance with all applicable laws and regulations and all UK, U.S. and
local or foreign export and re-export restrictions applicable to the technology and local or foreign export and re-export restrictions applicable to the technology and
documentation provided under this Agreement (including privacy and data security laws and documentation provided under this Agreement (including privacy and data security laws and
regulations), and you will not develop any Ultraleap Enabled Application which would commit or regulations), and you will not develop any Ultraleap Enabled Application which would commit or
facilitate the commission of a crime, or other tortious, unlawful, or illegal act. facilitate the commission of a crime, or other tortious, unlawful, or illegal act.
11. Agreement and Development Program 11. Agreement and Development Program
11.1. We reserve the right to change this Agreement, the SDK or the Ultraleap development and 11.1. We reserve the right to change this Agreement, the SDK or the Ultraleap development and
licensing program at any time in our discretion. Ultraleap may require that you either accept licensing program at any time in our discretion. Ultraleap may require that you either accept
and agree to the new terms of this Agreement, or, if you do not agree to the new terms, cease and agree to the new terms of this Agreement, or, if you do not agree to the new terms, cease
or terminate your use of the SDK. Your continued use of the SDK after changes to this or terminate your use of the SDK. Your continued use of the SDK after changes to this
Agreement take effect will constitute your acceptance of the changes. If you do not agree to a Agreement take effect will constitute your acceptance of the changes. If you do not agree to a
change, you must stop using the SDK and terminate this Agreement. Any termination of this change, you must stop using the SDK and terminate this Agreement. Any termination of this
Agreement by you under this Section 11 (and only this Section 11) will not affect your right, Agreement by you under this Section 11 (and only this Section 11) will not affect your right,
subject to your continued compliance with your obligations under this Agreement, to continue subject to your continued compliance with your obligations under this Agreement, to continue
to distribute versions of your Ultraleap Enabled Application created and first distributed before to distribute versions of your Ultraleap Enabled Application created and first distributed before
termination, and will not affect the right of your End Users to continue using such versions of termination, and will not affect the right of your End Users to continue using such versions of
your Ultraleap Enabled Application, both of which rights will survive termination. your Ultraleap Enabled Application, both of which rights will survive termination.
12. Term and Termination 12. Term and Termination
12.1. Term. This Agreement will continue to apply until terminated by either you or Ultraleap as set 12.1. Term. This Agreement will continue to apply until terminated by either you or Ultraleap as set
out below. out below.
12.2. Termination by You. If you want to terminate this Agreement, you may terminate it by 12.2. Termination by You. If you want to terminate this Agreement, you may terminate it by
uninstalling and destroying all copies of the SDK that are in the possession, custody or control of uninstalling and destroying all copies of the SDK that are in the possession, custody or control of
you, your Authorized Users and your organization. you, your Authorized Users and your organization.
12.3. Termination by Ultraleap. Ultraleap may at any time, terminate this Agreement with you for 12.3. Termination by Ultraleap. Ultraleap may at any time, terminate this Agreement with you for
any reason or for no reason in Ultraleaps sole discretion, including as a result of non- any reason or for no reason in Ultraleaps sole discretion, including as a result of non-
compliance by you with the restrictions in in this Agreement, or for other reasons. compliance by you with the restrictions in in this Agreement, or for other reasons.
12.4. Effect of Termination. Upon termination of this Agreement, all rights granted to you under this 12.4. Effect of Termination. Upon termination of this Agreement, all rights granted to you under this
Agreement will immediately terminate and you must immediately cease all use and destroy all Agreement will immediately terminate and you must immediately cease all use and destroy all
copies of the SDK in your and your Authorized Users possession, custody or control, and, except copies of the SDK in your and your Authorized Users possession, custody or control, and, except
as specifically set out in Section 11, cease your distribution of Ultraleap Enabled Applications. as specifically set out in Section 11, cease your distribution of Ultraleap Enabled Applications.
Sections 3, 8.1, 8.2, 9, 12.4, 14-16, and 17, will survive termination of this Agreement. Sections 3, 8.1, 8.2, 9, 12.4, 14-16, and 17, will survive termination of this Agreement.
Termination of this Agreement will not affect the right of your End Users who have downloaded Termination of this Agreement will not affect the right of your End Users who have downloaded
your Ultraleap Enabled Application prior to termination to continue using it. your Ultraleap Enabled Application prior to termination to continue using it.
13. Indemnification. 13. Indemnification.
13.1. You agree to indemnify, hold harmless and, at Ultraleaps option, defend Ultraleap and its 13.1. You agree to indemnify, hold harmless and, at Ultraleaps option, defend Ultraleap and its
affiliates and their respective officers, directors, employees, agents, and representatives affiliates and their respective officers, directors, employees, agents, and representatives
harmless from any and all judgments, awards, settlements, liabilities, damages, costs, penalties, harmless from any and all judgments, awards, settlements, liabilities, damages, costs, penalties,
fines and other expenses (including court costs and reasonable attorneys fees) incurred by fines and other expenses (including court costs and reasonable attorneys fees) incurred by
them arising out of or relating to any third party claim (a) with respect to your Ultraleap Enabled them arising out of or relating to any third party claim (a) with respect to your Ultraleap Enabled
Application, including products liability, privacy, or intellectual property infringement claims, or Application, including products liability, privacy, or intellectual property infringement claims, or
(b) based upon your negligence or wilful misconduct or any breach or alleged breach of your (b) based upon your negligence or wilful misconduct or any breach or alleged breach of your
representations, warranties, and covenants under this Agreement. In no event may you enter representations, warranties, and covenants under this Agreement. In no event may you enter
into any settlement or like agreement with a third party that affects Ultraleaps rights or binds into any settlement or like agreement with a third party that affects Ultraleaps rights or binds
Ultraleap or its affiliates in any way, without the prior written consent of Ultraleap. Ultraleap or its affiliates in any way, without the prior written consent of Ultraleap.
14. Warranty Disclaimer. 14. Warranty Disclaimer.
14.1. THE SDK, THE ULTRALEAP SOFTWARE AND THE ULTRALEAP REDISTRIBUTABLES ARE PROVIDED 14.1. THE SDK, THE ULTRALEAP SOFTWARE AND THE ULTRALEAP REDISTRIBUTABLES ARE PROVIDED
"AS IS" WITHOUT WARRANTY OF ANY KIND. ULTRALEAP, ON BEHALF OF ITSELF AND ITS "AS IS" WITHOUT WARRANTY OF ANY KIND. ULTRALEAP, ON BEHALF OF ITSELF AND ITS
SUPPLIERS, HEREBY DISCLAIMS ALL REPRESENTATIONS, PROMISES, OR WARRANTIES, WHETHER SUPPLIERS, HEREBY DISCLAIMS ALL REPRESENTATIONS, PROMISES, OR WARRANTIES, WHETHER
EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SDK, THE ULTRALEAP EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SDK, THE ULTRALEAP
SOFTWARE AND THE ULTRALEAP REDISTRIBUTABLES, INCLUDING THEIR CONDITION, SOFTWARE AND THE ULTRALEAP REDISTRIBUTABLES, INCLUDING THEIR CONDITION,
AVAILABILITY, OR THE EXISTENCE OF ANY LATENT DEFECTS, AND ULTRALEAP SPECIFICALLY AVAILABILITY, OR THE EXISTENCE OF ANY LATENT DEFECTS, AND ULTRALEAP SPECIFICALLY
DISCLAIMS ALL IMPLIED WARRANTIES OF MERCHANTABILITY, TITLE, NONINFRINGEMENT, DISCLAIMS ALL IMPLIED WARRANTIES OF MERCHANTABILITY, TITLE, NONINFRINGEMENT,
SUITABILITY, AND FITNESS FOR ANY PURPOSE. ULTRALEAP DOES NOT WARRANT THAT THE SDK, SUITABILITY, AND FITNESS FOR ANY PURPOSE. ULTRALEAP DOES NOT WARRANT THAT THE SDK,
THE ULTRALEAP SOFTWARE OR THE ULTALEAP REDISTRIBUTABLES WILL BE ERROR-FREE OR THE ULTRALEAP SOFTWARE OR THE ULTALEAP REDISTRIBUTABLES WILL BE ERROR-FREE OR
THAT THEY WILL WORK WITHOUT INTERRUPTION. THAT THEY WILL WORK WITHOUT INTERRUPTION.
15. Limitation of Liability. 15. Limitation of Liability.
15.1. ULTRALEAP SHALL NOT IN ANY CIRCUMSTANCES WHATEVER BE LIABLE TO YOU, WHETHER IN 15.1. ULTRALEAP SHALL NOT IN ANY CIRCUMSTANCES WHATEVER BE LIABLE TO YOU, WHETHER IN
CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF STATUTORY DUTY, OR OTHERWISE, CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF STATUTORY DUTY, OR OTHERWISE,
ARISING UNDER OR IN CONNECTION WITH THE AGREEMENT FOR: ARISING UNDER OR IN CONNECTION WITH THE AGREEMENT FOR:
15.1.1. LOSS OF PROFITS, SALES, BUSINESS, OR REVENUE; 15.1.1. LOSS OF PROFITS, SALES, BUSINESS, OR REVENUE;
15.1.2. BUSINESS INTERRUPTION; 15.1.2. BUSINESS INTERRUPTION;
15.1.3. LOSS OF ANTICIPATED SAVINGS; 15.1.3. LOSS OF ANTICIPATED SAVINGS;
15.1.4. LOSS OR CORRUPTION OF DATA OR INFORMATION; 15.1.4. LOSS OR CORRUPTION OF DATA OR INFORMATION;
15.1.5. LOSS OF BUSINESS OPPORTUNITY, GOODWILL OR REPUTATION; OR 15.1.5. LOSS OF BUSINESS OPPORTUNITY, GOODWILL OR REPUTATION; OR
15.1.6. ANY INDIRECT OR CONSEQUENTIAL LOSS OR DAMAGE. 15.1.6. ANY INDIRECT OR CONSEQUENTIAL LOSS OR DAMAGE.
15.2. OTHER THAN THE LOSSES SET OUT ABOVE (FOR WHICH ULTRALEAP IS NOT LIABLE), 15.2. OTHER THAN THE LOSSES SET OUT ABOVE (FOR WHICH ULTRALEAP IS NOT LIABLE),
ULTRALEAPS MAXIMUM AGGREGATE LIABILITY UNDER OR IN CONNECTION WITH THE ULTRALEAPS MAXIMUM AGGREGATE LIABILITY UNDER OR IN CONNECTION WITH THE
AGREEMENT WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF STATUTORY AGREEMENT WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF STATUTORY
DUTY, OR OTHERWISE, SHALL IN ALL CIRCUMSTANCES BE LIMITED TO $1,000 (ONE THOUSAND DUTY, OR OTHERWISE, SHALL IN ALL CIRCUMSTANCES BE LIMITED TO $1,000 (ONE THOUSAND
US DOLLARS). THIS MAXIMUM CAP DOES NOT APPLY TO DEATH OR PERSONAL INJURY US DOLLARS). THIS MAXIMUM CAP DOES NOT APPLY TO DEATH OR PERSONAL INJURY
RESULTING FROM ULTRALEAP'S NEGLIGENCE; FRAUD OR FRAUDULENT MISREPRESENTATION; RESULTING FROM ULTRALEAP'S NEGLIGENCE; FRAUD OR FRAUDULENT MISREPRESENTATION;
OR ANY OTHER LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED BY APPLICABLE LAW. OR ANY OTHER LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED BY APPLICABLE LAW.
15.3. THE AGREEMENT SETS OUT THE FULL EXTENT OF ULTRALEAPS OBLIGATIONS AND LIABILITIES IN 15.3. THE AGREEMENT SETS OUT THE FULL EXTENT OF ULTRALEAPS OBLIGATIONS AND LIABILITIES IN
RESPECT OF THE SUPPLY OF THE ULTRALEAP DEVICES, DELIVERABLES AND SOFTWARE. EXCEPT RESPECT OF THE SUPPLY OF THE ULTRALEAP DEVICES, DELIVERABLES AND SOFTWARE. EXCEPT
AS EXPRESSLY STATED IN THE AGREEMENT, THERE ARE NO CONDITIONS, WARRANTIES, AS EXPRESSLY STATED IN THE AGREEMENT, THERE ARE NO CONDITIONS, WARRANTIES,
REPRESENTATIONS OR OTHER TERMS, EXPRESS OR IMPLIED, THAT ARE BINDING ON REPRESENTATIONS OR OTHER TERMS, EXPRESS OR IMPLIED, THAT ARE BINDING ON
ULTRALEAP. ANY CONDITION, WARRANTY, REPRESENTATION OR OTHER TERM CONCERNING ULTRALEAP. ANY CONDITION, WARRANTY, REPRESENTATION OR OTHER TERM CONCERNING
THE SUPPLY OF THE ULTRALEAP HARDWARE, ULTRALEAP SOFTWARE, THE SDK, THE ULTRALEAP THE SUPPLY OF THE ULTRALEAP HARDWARE, ULTRALEAP SOFTWARE, THE SDK, THE ULTRALEAP
REDISTRIBUTABLES, OR ANY OTHER ULTRALEAP TECHNOLOGY WHICH MIGHT OTHERWISE BE REDISTRIBUTABLES, OR ANY OTHER ULTRALEAP TECHNOLOGY WHICH MIGHT OTHERWISE BE
IMPLIED INTO, OR INCORPORATED IN THE AGREEMENT WHETHER BY STATUTE, COMMON LAW IMPLIED INTO, OR INCORPORATED IN THE AGREEMENT WHETHER BY STATUTE, COMMON LAW
OR OTHERWISE, INCLUDING ANY WARRANTY OR CONDITION OF MERCHANTABILITY OR FITNESS OR OTHERWISE, INCLUDING ANY WARRANTY OR CONDITION OF MERCHANTABILITY OR FITNESS
FOR A PARTICULAR PURPOSE, IS EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW. THESE FOR A PARTICULAR PURPOSE, IS EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW. THESE
LIMITATIONS WILL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITATIONS WILL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY
LIMITED REMEDY. THE PARTIES AGREE THAT THE FOREGOING LIMITATIONS REPRESENT A LIMITED REMEDY. THE PARTIES AGREE THAT THE FOREGOING LIMITATIONS REPRESENT A
REASONABLE ALLOCATION OF RISK UNDER THIS AGREEMENT. REASONABLE ALLOCATION OF RISK UNDER THIS AGREEMENT.
16. Miscellaneous. 16. Miscellaneous.
16.1. Assignment. You may not assign this Agreement without the prior written consent of Ultraleap. 16.1. Assignment. You may not assign this Agreement without the prior written consent of Ultraleap.
Any assignment without such consent is void and of no effect. Ultraleap may assign this Any assignment without such consent is void and of no effect. Ultraleap may assign this
Agreement without your consent in connection with (a) a merger or consolidation of Ultraleap, Agreement without your consent in connection with (a) a merger or consolidation of Ultraleap,
(b) a sale or assignment of substantially all its assets, or (c) any other transaction which results (b) a sale or assignment of substantially all its assets, or (c) any other transaction which results
in another entity or person owning substantially all of the assets of Ultraleap, or (d) to any of its in another entity or person owning substantially all of the assets of Ultraleap, or (d) to any of its
affiliates. In the event of a permitted assignment, this Agreement will inure to the benefit of and affiliates. In the event of a permitted assignment, this Agreement will inure to the benefit of and
be binding upon the parties and their respective successors and permitted assigns. be binding upon the parties and their respective successors and permitted assigns.
16.2. Waiver; Severability. The failure of the other party to enforce any rights under this Agreement 16.2. Waiver; Severability. The failure of the other party to enforce any rights under this Agreement
will not be deemed a waiver of any rights. The rights and remedies of the parties in this will not be deemed a waiver of any rights. The rights and remedies of the parties in this
Agreement are not exclusive and are in addition to any other rights and remedies provided by Agreement are not exclusive and are in addition to any other rights and remedies provided by
law. If any provision of this Agreement is held by a court of competent jurisdiction to be law. If any provision of this Agreement is held by a court of competent jurisdiction to be
contrary to law, the remaining provisions of this Agreement will remain in full force and effect. contrary to law, the remaining provisions of this Agreement will remain in full force and effect.
16.3. Reservation. All licenses not expressly granted in this Agreement are reserved and no other 16.3. Reservation. All licenses not expressly granted in this Agreement are reserved and no other
licenses, immunity or rights, express or implied, are granted by Ultraleap, by implication, licenses, immunity or rights, express or implied, are granted by Ultraleap, by implication,
estoppel, or otherwise. The software in the SDK is licensed, not sold. estoppel, or otherwise. The software in the SDK is licensed, not sold.
16.4. Export Restrictions. The Ultraleap Software is subject to United States and UK export laws and 16.4. Export Restrictions. The Ultraleap Software is subject to United States and UK export laws and
regulations. You must comply with all domestic and international export laws and regulations regulations. You must comply with all domestic and international export laws and regulations
that apply to the Ultraleap Software. These laws include restrictions on destinations, end users, that apply to the Ultraleap Software. These laws include restrictions on destinations, end users,
and end use. and end use.
16.5. Governing Law and Jurisdiction. This Agreement will be exclusively governed by and construed 16.5. Governing Law and Jurisdiction. This Agreement will be exclusively governed by and construed
under the laws of the England and Wales, without reference to or application of rules governing under the laws of the England and Wales, without reference to or application of rules governing
choice of laws. All disputes arising out of or related to this Agreement will be subject to the choice of laws. All disputes arising out of or related to this Agreement will be subject to the
exclusive jurisdiction of courts of England and you hereby consent to such jurisdiction. However, exclusive jurisdiction of courts of England and you hereby consent to such jurisdiction. However,
Ultraleap may apply to any court or tribunal worldwide, including but not limited to those Ultraleap may apply to any court or tribunal worldwide, including but not limited to those
having jurisdiction over you or your Authorized Users, to seek injunctive relief. having jurisdiction over you or your Authorized Users, to seek injunctive relief.
16.6. Relationship of the Parties. This Agreement does not create any agency, partnership, or joint 16.6. Relationship of the Parties. This Agreement does not create any agency, partnership, or joint
venture relationship between Ultraleap and you. This Agreement is for the sole benefit of venture relationship between Ultraleap and you. This Agreement is for the sole benefit of
Ultraleap and you (and indemnified parties), and no other persons will have any right or remedy Ultraleap and you (and indemnified parties), and no other persons will have any right or remedy
under this Agreement. under this Agreement.
16.7. Notices. The address for notice to Ultraleap under this Agreement is: 16.7. Notices. The address for notice to Ultraleap under this Agreement is:
Ultraleap Limited Ultraleap Limited
The West Wing The West Wing
Glass Wharf Glass Wharf
Bristol, BS2 0EL Bristol, BS2 0EL
United Kingdom United Kingdom
Ultraleap may provide you notice under this Agreement by email or other electronic Ultraleap may provide you notice under this Agreement by email or other electronic
communication or by posting communications to its development community on the Ultraleap communication or by posting communications to its development community on the Ultraleap
developer portal. You consent to receive such notices in any of the foregoing manners and developer portal. You consent to receive such notices in any of the foregoing manners and
agree that any such notices by Ultraleap will satisfy any legal communication requirements. agree that any such notices by Ultraleap will satisfy any legal communication requirements.
16.8. Entire Agreement. This Agreement is the entire understanding of the parties with respect to its 16.8. Entire Agreement. This Agreement is the entire understanding of the parties with respect to its
subject matter and supersedes any previous or contemporaneous communications, whether subject matter and supersedes any previous or contemporaneous communications, whether
oral or written with respect to such subject matter. oral or written with respect to such subject matter.
17. Definitions 17. Definitions
Whenever capitalized in this Agreement: Whenever capitalized in this Agreement:
“Authorized Users” means your employees and contractors, members of your organization or, if you “Authorized Users” means your employees and contractors, members of your organization or, if you
are an educational institution, your faculty, staff and registered students, who (a) have a are an educational institution, your faculty, staff and registered students, who (a) have a
demonstrable need to know or use the SDK in order to develop and test Ultraleap Enabled demonstrable need to know or use the SDK in order to develop and test Ultraleap Enabled
Applications on your behalf and (b) each have written and binding agreements with you to protect Applications on your behalf and (b) each have written and binding agreements with you to protect
against the unauthorized use and disclosure of the SDK consistent with the terms and conditions of against the unauthorized use and disclosure of the SDK consistent with the terms and conditions of
this Agreement. Authorized Users do not include End Users. this Agreement. Authorized Users do not include End Users.
“End User” means your end user customer(s) or licensee(s). “End User” means your end user customer(s) or licensee(s).
“Non-Redistributable Materials” means the Ultraleap Software, and any other code, files or “Non-Redistributable Materials” means the Ultraleap Software, and any other code, files or
materials that are not specifically designated in the SDK as made available for incorporation into materials that are not specifically designated in the SDK as made available for incorporation into
Ultraleap Enabled Applications or that are specifically designated in the SDK as not subject to Ultraleap Enabled Applications or that are specifically designated in the SDK as not subject to
distribution. distribution.
“SDK” means, collectively, the Ultraleap Redistributables, tools, APIs, sample code, software, “SDK” means, collectively, the Ultraleap Redistributables, tools, APIs, sample code, software,
documentation, other materials and any updates to the foregoing that may be provided or made documentation, other materials and any updates to the foregoing that may be provided or made
available to you by Ultraleap in connection with this Agreement, via the Ultraleap developer portal or available to you by Ultraleap in connection with this Agreement, via the Ultraleap developer portal or
otherwise for use in connection with the Ultraleap development program to develop Ultraleap otherwise for use in connection with the Ultraleap development program to develop Ultraleap
Enabled Applications. Enabled Applications.
“Specialized Application” means an Ultraleap Enabled Application which does not fall within the “Specialized Application” means an Ultraleap Enabled Application which does not fall within the
permitted uses set out in this Agreement. permitted uses set out in this Agreement.
“Ultraleap” “we” or “us” means Ultraleap Limited, a company registered in England with company “Ultraleap” “we” or “us” means Ultraleap Limited, a company registered in England with company
number 08781720, with a principal place of business at The West Wing, Glass Wharf, Bristol, BS2 0EL, number 08781720, with a principal place of business at The West Wing, Glass Wharf, Bristol, BS2 0EL,
United Kingdom. United Kingdom.
“Ultraleap Hardware” means the Leap Motion Controller, Stereo IR 170, Stereo IR 170 EK or Ultraleap 3Di each being a device that “Ultraleap Hardware” means the Leap Motion Controller, Stereo IR 170, Stereo IR 170 EK or Ultraleap 3Di each being a device that
detects and reads movements within a 3-D interaction space to precisely interact with and control detects and reads movements within a 3-D interaction space to precisely interact with and control
software on a computing device, or an Ultraleap-authorized embedded optical module. software on a computing device, or an Ultraleap-authorized embedded optical module.
“Ultraleap Redistributables” means any .lib code, .dll files, .so files, sample code, or other materials “Ultraleap Redistributables” means any .lib code, .dll files, .so files, sample code, or other materials
we specifically designate in the SDK as made available for incorporation into or distribution with we specifically designate in the SDK as made available for incorporation into or distribution with
Ultraleap Enabled Applications. Ultraleap Enabled Applications.
“Ultraleap Software” means the Ultraleap core services application and related applications that “Ultraleap Software” means the Ultraleap core services application and related applications that
interact with Ultraleap Hardware and an operating system to make motion control functionality interact with Ultraleap Hardware and an operating system to make motion control functionality
available to Ultraleap Enabled Applications, and includes any Updates thereto. available to Ultraleap Enabled Applications, and includes any Updates thereto.
“Updates” means updates, upgrades, modifications, enhancements, revisions, new releases or new “Updates” means updates, upgrades, modifications, enhancements, revisions, new releases or new
versions to the SDK that Ultraleap may make available to you in connection with this Agreement. versions to the SDK that Ultraleap may make available to you in connection with this Agreement.
Other capitalized terms used in this Agreement have the meaning given them elsewhere in this Other capitalized terms used in this Agreement have the meaning given them elsewhere in this
Agreement. Agreement.
18. Supplemental Terms Applicable to the Use of Image API 18. Supplemental Terms Applicable to the Use of Image API
18.1. Purpose. You and/or your Ultraleap Enabled Application may access the Image API and use 18.1. Purpose. You and/or your Ultraleap Enabled Application may access the Image API and use
image data available through the Image API only for the purpose of developing and testing image data available through the Image API only for the purpose of developing and testing
Ultraleap Enabled Applications, and only for use with Ultraleap Hardware. You may not use the Ultraleap Enabled Applications, and only for use with Ultraleap Hardware. You may not use the
Image API to develop or aid development of competing motion tracking hardware or software. Image API to develop or aid development of competing motion tracking hardware or software.
Any use of the Image API is subject to the terms of the Agreement. Any use of the Image API is subject to the terms of the Agreement.
18.2. Data Protection. 18.2. Data Protection.
18.2.1. If you or your Ultraleap Enabled Application collects, uploads, stores, transmits, or 18.2.1. If you or your Ultraleap Enabled Application collects, uploads, stores, transmits, or
shares images, videos, or other personal information available through the Image API, shares images, videos, or other personal information available through the Image API,
either through or in connection with your Ultraleap Enabled Application, you must either through or in connection with your Ultraleap Enabled Application, you must
expressly provide users with your privacy policy and adhere to it. expressly provide users with your privacy policy and adhere to it.
18.2.2. You must obtain specific, opt-in consent from the user for any use that is beyond the 18.2.2. You must obtain specific, opt-in consent from the user for any use that is beyond the
limited and express purpose of your Ultraleap Enabled Application. limited and express purpose of your Ultraleap Enabled Application.
18.2.3. You and your Ultraleap Enabled Application must use and store information collected 18.2.3. You and your Ultraleap Enabled Application must use and store information collected
form users securely and only for as long as it is required. form users securely and only for as long as it is required.
18.2.4. You agree that you will protect the privacy and legal rights of users, and will comply with 18.2.4. You agree that you will protect the privacy and legal rights of users, and will comply with
all applicable criminal, civil, and statutory privacy and data protection laws and all applicable criminal, civil, and statutory privacy and data protection laws and
regulations. regulations.

View file

@ -1,159 +1,159 @@
# Ultraleap SDK # Ultraleap SDK
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
## Package contents: ## Package contents:
LeapSDK LeapSDK
- include - include
* API headers. * API headers.
- lib - lib
* dynamic API library and CMake scripts. * dynamic API library and CMake scripts.
- samples - samples
* Various samples demonstrating several different usages. * Various samples demonstrating several different usages.
- LICENSE.md - LICENSE.md
* Ultraleap Tracking SDK license. * Ultraleap Tracking SDK license.
- README.md - README.md
* Ultraleap Tracking SDK readme. * Ultraleap Tracking SDK readme.
- ThirdPartyNotices.md - ThirdPartyNotices.md
* Ultraleap Tracking SDK third party licenses. * Ultraleap Tracking SDK third party licenses.
## Requirements: ## Requirements:
1. Running requires 1. Running requires
* Ultraleap Tracking Software https://developer.leapmotion.com/get-started/ * Ultraleap Tracking Software https://developer.leapmotion.com/get-started/
2. Building Samples requires 2. Building Samples requires
* CMake 3.16.3+ (https://cmake.org/) * CMake 3.16.3+ (https://cmake.org/)
* Microsoft Visual Studio 15+ (Windows) * Microsoft Visual Studio 15+ (Windows)
* GCC (Linux - tested on v9.4.0) * GCC (Linux - tested on v9.4.0)
## Installation: ## Installation:
The LeapSDK is installed with Ultraleap Tracking. The LeapSDK is installed with Ultraleap Tracking.
## Usage: ## Usage:
1. For CMake projects 1. For CMake projects
* Ensure LeapSDK is in a directory considered as a prefix by find_package. * Ensure LeapSDK is in a directory considered as a prefix by find_package.
(https://cmake.org/cmake/help/v3.16/command/find_package.html) (https://cmake.org/cmake/help/v3.16/command/find_package.html)
* Or : directly set LeapSDK_DIR to <install_dir>/LeapSDK/lib/cmake/LeapSDK * Or : directly set LeapSDK_DIR to <install_dir>/LeapSDK/lib/cmake/LeapSDK
* Or : Pass the LeapSDK's path to find_package with the PATHS option. * Or : Pass the LeapSDK's path to find_package with the PATHS option.
* call find_package(LeapSDK 5 [PATHS ...]). * call find_package(LeapSDK 5 [PATHS ...]).
* call target_link_libraries(<your project> PUBLIC|PRIVATE LeapSDK::LeapC). * call target_link_libraries(<your project> PUBLIC|PRIVATE LeapSDK::LeapC).
* Ensure LeapC.dll/LeapC.so is in your dynamic library search path. * Ensure LeapC.dll/LeapC.so is in your dynamic library search path.
* A popular option is to add a post-build step that copies it to your project's output directory. * A popular option is to add a post-build step that copies it to your project's output directory.
2. For non-CMake projects 2. For non-CMake projects
* Use a C/C++ compiler such as MSVC, Clang or GCC. * Use a C/C++ compiler such as MSVC, Clang or GCC.
* Add LeapSDK/include to the compiler include search paths. * Add LeapSDK/include to the compiler include search paths.
* Either add a linker reference to LeapC.lib or dynamically load LeapC.dll/LeapC.so. * Either add a linker reference to LeapC.lib or dynamically load LeapC.dll/LeapC.so.
## Building Samples: ## Building Samples:
### Windows ### Windows
1. Open CMake using LeapSDK/samples as the source directory 1. Open CMake using LeapSDK/samples as the source directory
2. Select a build directory (often LeapSDK/samples/build) to use 2. Select a build directory (often LeapSDK/samples/build) to use
3. Configure & Generate CMake with the generator of your choice 3. Configure & Generate CMake with the generator of your choice
4. Open and build the CMake generated project files. For more help, see the CMake documentation. 4. Open and build the CMake generated project files. For more help, see the CMake documentation.
* An example script would be : * An example script would be :
```powershell ```powershell
$env:BUILD_TYPE = 'Release' $env:BUILD_TYPE = 'Release'
$env:REPOS_BUILD_ROOT = 'C:/build' $env:REPOS_BUILD_ROOT = 'C:/build'
$env:REPOS_INSTALL_ROOT = 'C:/Program Files' $env:REPOS_INSTALL_ROOT = 'C:/Program Files'
cmake -S "C:/Program Files/Ultraleap/LeapSDK/samples" -B $env:REPOS_BUILD_ROOT/$env:BUILD_TYPE/LeapSDK/leapc_example ` cmake -S "C:/Program Files/Ultraleap/LeapSDK/samples" -B $env:REPOS_BUILD_ROOT/$env:BUILD_TYPE/LeapSDK/leapc_example `
-DCMAKE_INSTALL_PREFIX="$env:REPOS_INSTALL_ROOT/leapc_example" ` -DCMAKE_INSTALL_PREFIX="$env:REPOS_INSTALL_ROOT/leapc_example" `
-DCMAKE_BUILD_TYPE="$env:BUILD_TYPE" -DCMAKE_BUILD_TYPE="$env:BUILD_TYPE"
cmake --build $env:REPOS_BUILD_ROOT/$env:BUILD_TYPE/LeapSDK/leapc_example -j --config $env:BUILD_TYPE cmake --build $env:REPOS_BUILD_ROOT/$env:BUILD_TYPE/LeapSDK/leapc_example -j --config $env:BUILD_TYPE
``` ```
### x64 Linux ### x64 Linux
1. Open CMake using /usr/share/doc/ultraleap-hand-tracking-service/samples as the source directory 1. Open CMake using /usr/share/doc/ultraleap-hand-tracking-service/samples as the source directory
2. Select a build directory (eg. ~/ultraleap-tracking-samples/build) to use 2. Select a build directory (eg. ~/ultraleap-tracking-samples/build) to use
3. Configure & Generate CMake with the generator of your choice 3. Configure & Generate CMake with the generator of your choice
4. Open and build the CMake generated project files. For more help, see the CMake documentation. 4. Open and build the CMake generated project files. For more help, see the CMake documentation.
* An example script would be : * An example script would be :
```bash ```bash
SRC_DIR=/usr/share/doc/ultraleap-hand-tracking-service/samples SRC_DIR=/usr/share/doc/ultraleap-hand-tracking-service/samples
BUILD_TYPE='Release' BUILD_TYPE='Release'
REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build
REPOS_INSTALL_ROOT=/usr/bin/ultraleap-tracking-samples REPOS_INSTALL_ROOT=/usr/bin/ultraleap-tracking-samples
cmake -S ${SRC_DIR} -B ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example ` cmake -S ${SRC_DIR} -B ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example `
-DCMAKE_INSTALL_PREFIX="${REPOS_INSTALL_ROOT}/leapc_example" ` -DCMAKE_INSTALL_PREFIX="${REPOS_INSTALL_ROOT}/leapc_example" `
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}"
cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --config ${BUILD_TYPE} cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --config ${BUILD_TYPE}
``` ```
### ARM64 Linux ### ARM64 Linux
1. Open the top level directory of the untarred release and select a build directory (eg. ~/ultraleap-tracking-samples/build) to use 1. Open the top level directory of the untarred release and select a build directory (eg. ~/ultraleap-tracking-samples/build) to use
2. Set the CMAKE_PREFIX_PATH directory to the absolute location of LeapSDK 2. Set the CMAKE_PREFIX_PATH directory to the absolute location of LeapSDK
3. Configure & Generate CMake with the generator of your choice 3. Configure & Generate CMake with the generator of your choice
4. Open and build the CMake generated project files. For more help, see the CMake documentation. 4. Open and build the CMake generated project files. For more help, see the CMake documentation.
* An example script would be : * An example script would be :
```bash ```bash
SRC_DIR='LeapSDK/samples' SRC_DIR='LeapSDK/samples'
BUILD_TYPE='Release' BUILD_TYPE='Release'
REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build
REPOS_INSTALL_ROOT=~/ultraleap-tracking-samples/bin REPOS_INSTALL_ROOT=~/ultraleap-tracking-samples/bin
PREFIX_PATH=$(pwd)/LeapSDK PREFIX_PATH=$(pwd)/LeapSDK
cmake -S ${SRC_DIR} -B ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example ` cmake -S ${SRC_DIR} -B ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example `
-DCMAKE_INSTALL_PREFIX="${REPOS_INSTALL_ROOT}/leapc_example"` -DCMAKE_INSTALL_PREFIX="${REPOS_INSTALL_ROOT}/leapc_example"`
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_PREFIX_PATH="${PREFIX_PATH}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_PREFIX_PATH="${PREFIX_PATH}"
cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --config ${BUILD_TYPE} cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --config ${BUILD_TYPE}
``` ```
### MacOS ### MacOS
1. Open CMake using /Applications/Ultraleap\ Hand\ Tracking.app/Contents/LeapSDK/samples as the source directory 1. Open CMake using /Applications/Ultraleap\ Hand\ Tracking.app/Contents/LeapSDK/samples as the source directory
2. Select a build directory (eg. ~/ultraleap-tracking-samples/build) to use 2. Select a build directory (eg. ~/ultraleap-tracking-samples/build) to use
3. Configure & Generate CMake with the generator of your choice 3. Configure & Generate CMake with the generator of your choice
4. Open and build the CMake generated project files. For more help, see the CMake documentation. 4. Open and build the CMake generated project files. For more help, see the CMake documentation.
* An example script would be : * An example script would be :
```bash ```bash
SRC_DIR='/Applications/Ultraleap\ Hand\ Tracking.app/Contents/LeapSDK/samples' SRC_DIR='/Applications/Ultraleap\ Hand\ Tracking.app/Contents/LeapSDK/samples'
BUILD_TYPE='Release' BUILD_TYPE='Release'
REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build
REPOS_INSTALL_ROOT=~/ultraleap-tracking-samples/bin REPOS_INSTALL_ROOT=~/ultraleap-tracking-samples/bin
cmake -S ${SRC_DIR} -B ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example ` cmake -S ${SRC_DIR} -B ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example `
-DCMAKE_INSTALL_PREFIX="${REPOS_INSTALL_ROOT}/leapc_example" ` -DCMAKE_INSTALL_PREFIX="${REPOS_INSTALL_ROOT}/leapc_example" `
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}"
cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --config ${BUILD_TYPE} cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --config ${BUILD_TYPE}
``` ```
## Resources: ## Resources:
1. Ultraleap For Developers Site (https://developer.leapmotion.com) 1. Ultraleap For Developers Site (https://developer.leapmotion.com)
provides examples, community forums, Ultraleap news, and documentation provides examples, community forums, Ultraleap news, and documentation
to help you to learn how to develop applications using the Ultraleap Tracking to help you to learn how to develop applications using the Ultraleap Tracking
SDK. SDK.
2. C# and Unity bindings (https://github.com/leapmotion/UnityModules) 2. C# and Unity bindings (https://github.com/leapmotion/UnityModules)
3. C++ bindings matching the old API (https://github.com/leapmotion/LeapCxx) 3. C++ bindings matching the old API (https://github.com/leapmotion/LeapCxx)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Copyright © 2012-2020 Ultraleap Ltd. All rights reserved. Copyright © 2012-2020 Ultraleap Ltd. All rights reserved.
Use subject to the terms of the Ultraleap Tracking SDK Agreement `LICENSE.md` next to this `README.md` file. Use subject to the terms of the Ultraleap Tracking SDK Agreement `LICENSE.md` next to this `README.md` file.

File diff suppressed because it is too large Load diff

View file

@ -1,32 +1,32 @@
Copyright 2008 Google Inc. All rights reserved. Copyright 2008 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
met: met:
* Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the in the documentation and/or other materials provided with the
distribution. distribution.
* Neither the name of Google Inc. nor the names of its * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Code generated by the Protocol Buffer compiler is owned by the owner Code generated by the Protocol Buffer compiler is owned by the owner
of the input file used when generating it. This code is not of the input file used when generating it. This code is not
standalone and requires a support library to be linked with it. This standalone and requires a support library to be linked with it. This
support library is itself covered by the above license. support library is itself covered by the above license.

Binary file not shown.

View file

@ -48,6 +48,9 @@ namespace ml_pam
HandState m_leftHandState = HandState.Empty; HandState m_leftHandState = HandState.Empty;
HandState m_rightHandState = HandState.Empty; HandState m_rightHandState = HandState.Empty;
AvatarBoolParameter m_leftHandParameter = null;
AvatarBoolParameter m_rightHandParameter = null;
// Unity events // Unity events
void Start() void Start()
{ {
@ -239,7 +242,7 @@ namespace ml_pam
{ {
m_enabled = p_state; m_enabled = p_state;
if(m_enabled) if(p_state)
{ {
if(m_leftHandState != HandState.Empty) if(m_leftHandState != HandState.Empty)
SetArmActive(Settings.LeadHand.Left, true); SetArmActive(Settings.LeadHand.Left, true);
@ -335,6 +338,8 @@ namespace ml_pam
m_armIKLeft = null; m_armIKLeft = null;
m_armIKRight = null; m_armIKRight = null;
m_armLength = 0f; m_armLength = 0f;
m_leftHandParameter = null;
m_rightHandParameter = null;
} }
void OnAvatarSetup() void OnAvatarSetup()
@ -365,6 +370,9 @@ namespace ml_pam
SetupArmIK(); SetupArmIK();
} }
m_leftHandParameter = new AvatarBoolParameter("LeftHandExtended", PlayerSetup.Instance.animatorManager);
m_rightHandParameter = new AvatarBoolParameter("RightHandExtended", PlayerSetup.Instance.animatorManager);
OnEnabledChanged(m_enabled); OnEnabledChanged(m_enabled);
} }
@ -533,6 +541,11 @@ namespace ml_pam
m_armIKRight.solver.IKPositionWeight = (p_state ? 1f : 0f); m_armIKRight.solver.IKPositionWeight = (p_state ? 1f : 0f);
m_armIKRight.solver.IKRotationWeight = (p_state ? 1f : 0f); m_armIKRight.solver.IKRotationWeight = (p_state ? 1f : 0f);
} }
if((p_hand == Settings.LeadHand.Left) || (p_hand == Settings.LeadHand.Both))
m_leftHandParameter?.SetValue(p_state);
if((p_hand == Settings.LeadHand.Right) || (p_hand == Settings.LeadHand.Both))
m_rightHandParameter?.SetValue(p_state);
} }
} }

View file

@ -0,0 +1,43 @@
using ABI_RC.Core.Util.AnimatorManager;
using System.Text.RegularExpressions;
using UnityEngine;
namespace ml_pam
{
class AvatarBoolParameter
{
public readonly string m_name;
public readonly int m_hash = 0;
public readonly bool m_sync;
readonly AvatarAnimatorManager m_manager = null;
public AvatarBoolParameter(string p_name, AvatarAnimatorManager p_manager)
{
m_name = p_name;
m_manager = p_manager;
Regex l_regex = new Regex("^#?" + p_name + '$');
foreach(var l_param in m_manager.Animator.parameters)
{
if(l_regex.IsMatch(l_param.name) && (l_param.type == AnimatorControllerParameterType.Bool))
{
m_name = l_param.name;
m_sync = !l_param.name.StartsWith('#');
m_hash = l_param.nameHash;
break;
}
}
}
public void SetValue(bool p_value)
{
if(m_hash != 0)
{
if(m_sync)
m_manager.SetParameter(m_name, p_value);
else
m_manager.Animator.SetBool(m_hash, p_value);
}
}
}
}

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(1)] [assembly: MelonLoader.MelonPriority(1)]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

@ -13,6 +13,9 @@ Available mod's settings in `Settings - Interactions - Pickup Arm Movement`:
* **Leading hand:** hand that will be extended when gragging pickup; available values: `Left`, `Right`, `Both`; default value - `Right`. * **Leading hand:** hand that will be extended when gragging pickup; available values: `Left`, `Right`, `Both`; default value - `Right`.
* **Hands extension (Q\E):** extend left and right hand if `Q` and `E` keys are pressed; default value - `true`. * **Hands extension (Q\E):** extend left and right hand if `Q` and `E` keys are pressed; default value - `true`.
Available animator boolean parameters:
* **LeftHandExtended:`` indicates if left hand is extended.
* **RightHandExtended:`` indicates if right hand is extended.
# Notes # Notes
* Made for desktop mode in mind. * Made for desktop mode in mind.
* Compatible with [DekstopVRIK](https://github.com/NotAKidOnSteam/NAK_CVR_Mods).

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<PackageId>PickupArmMovement</PackageId> <PackageId>PickupArmMovement</PackageId>
<Version>1.1.3</Version> <Version>1.1.4</Version>
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>None</Company> <Company>None</Company>
<Product>PickupArmMovement</Product> <Product>PickupArmMovement</Product>

View file

@ -41,11 +41,16 @@ namespace ml_pmc
HumanPose m_pose; HumanPose m_pose;
PuppetParser m_puppetParser = null; PuppetParser m_puppetParser = null;
void Awake()
{
if((Instance != null) && (Instance != this))
Object.Destroy(this);
else
Instance = this;
}
void Start() void Start()
{ {
if(Instance == null)
Instance = this;
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear); GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup); GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
GameEvents.OnAvatarPreReuse.AddHandler(this.OnAvatarPreReuse); GameEvents.OnAvatarPreReuse.AddHandler(this.OnAvatarPreReuse);

View file

@ -1,253 +1,253 @@
using ABI.CCK.Components; using ABI.CCK.Components;
using ABI_RC.Core; using ABI_RC.Core;
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Systems.IK; using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.Movement; using ABI_RC.Systems.Movement;
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
namespace ml_prm namespace ml_prm
{ {
static class GameEvents static class GameEvents
{ {
internal class EventResult internal class EventResult
{ {
public bool m_result = false; public bool m_result = false;
} }
internal class GameEvent internal class GameEvent
{ {
event Action m_action; event Action m_action;
public void AddHandler(Action p_listener) => m_action += p_listener; public void AddHandler(Action p_listener) => m_action += p_listener;
public void RemoveHandler(Action p_listener) => m_action -= p_listener; public void RemoveHandler(Action p_listener) => m_action -= p_listener;
public void Invoke() => m_action?.Invoke(); public void Invoke() => m_action?.Invoke();
} }
internal class GameEvent<T1> internal class GameEvent<T1>
{ {
event Action<T1> m_action; event Action<T1> m_action;
public void AddHandler(Action<T1> p_listener) => m_action += p_listener; public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener; public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj); public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
} }
public static readonly GameEvent OnAvatarSetup = new GameEvent(); public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent(); public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarPreReuse = new GameEvent(); public static readonly GameEvent OnAvatarPreReuse = new GameEvent();
public static readonly GameEvent OnAvatarPostReuse = new GameEvent(); public static readonly GameEvent OnAvatarPostReuse = new GameEvent();
public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>(); public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
public static readonly GameEvent<CVRSeat> OnSeatPreSit = new GameEvent<CVRSeat>(); public static readonly GameEvent<CVRSeat> OnSeatPreSit = new GameEvent<CVRSeat>();
public static readonly GameEvent OnCalibrationStart = new GameEvent(); public static readonly GameEvent OnCalibrationStart = new GameEvent();
public static readonly GameEvent OnWorldPreSpawn = new GameEvent(); public static readonly GameEvent OnWorldPreSpawn = new GameEvent();
public static readonly GameEvent OnCombatPreDown = new GameEvent(); public static readonly GameEvent OnCombatPreDown = new GameEvent();
public static readonly GameEvent OnFlightChange = new GameEvent(); public static readonly GameEvent OnFlightChange = new GameEvent();
public static readonly GameEvent<EventResult> OnIKOffsetUpdate = new GameEvent<EventResult>(); public static readonly GameEvent<EventResult> OnIKOffsetUpdate = new GameEvent<EventResult>();
static readonly EventResult ms_result = new EventResult(); static readonly EventResult ms_result = new EventResult();
internal static void Init(HarmonyLib.Harmony p_instance) internal static void Init(HarmonyLib.Harmony p_instance)
{ {
try try
{ {
p_instance.Patch( p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
null, null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static)) new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
); );
p_instance.Patch( p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)), typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
null, null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
); );
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
); );
p_instance.Patch( p_instance.Patch(
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance), typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
null, null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
); );
p_instance.Patch( p_instance.Patch(
typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown)), typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCVRSeatSitDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCVRSeatSitDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null null
); );
p_instance.Patch( p_instance.Patch(
typeof(BodySystem).GetMethod(nameof(BodySystem.StartCalibration)), typeof(BodySystem).GetMethod(nameof(BodySystem.StartCalibration)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnStartCalibration_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnStartCalibration_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null null
); );
p_instance.Patch( p_instance.Patch(
typeof(RootLogic).GetMethod(nameof(RootLogic.SpawnOnWorldInstance)), typeof(RootLogic).GetMethod(nameof(RootLogic.SpawnOnWorldInstance)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null null
); );
p_instance.Patch( p_instance.Patch(
typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))), typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null null
); );
p_instance.Patch( p_instance.Patch(
typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)), typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)),
null, null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
); );
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic), typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic)) new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
); );
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnAvatarClear_Postfix() static void OnAvatarClear_Postfix()
{ {
try try
{ {
OnAvatarClear.Invoke(); OnAvatarClear.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnSetupAvatar_Postfix() static void OnSetupAvatar_Postfix()
{ {
try try
{ {
OnAvatarSetup.Invoke(); OnAvatarSetup.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnAvatarReinitialize_Prefix() static void OnAvatarReinitialize_Prefix()
{ {
try try
{ {
OnAvatarPreReuse.Invoke(); OnAvatarPreReuse.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnAvatarReinitialize_Postfix() static void OnAvatarReinitialize_Postfix()
{ {
try try
{ {
OnAvatarPostReuse.Invoke(); OnAvatarPostReuse.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference) static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference)
{ {
try try
{ {
OnIKScaling.Invoke(1f + ___scaleDifference.y); OnIKScaling.Invoke(1f + ___scaleDifference.y);
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnCVRSeatSitDown_Prefix(ref CVRSeat __instance) static void OnCVRSeatSitDown_Prefix(ref CVRSeat __instance)
{ {
try try
{ {
OnSeatPreSit.Invoke(__instance); OnSeatPreSit.Invoke(__instance);
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnStartCalibration_Prefix() static void OnStartCalibration_Prefix()
{ {
try try
{ {
OnCalibrationStart.Invoke(); OnCalibrationStart.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnWorldSpawn_Prefix() static void OnWorldSpawn_Prefix()
{ {
try try
{ {
OnWorldPreSpawn.Invoke(); OnWorldPreSpawn.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnCombatDown_Prefix() static void OnCombatDown_Prefix()
{ {
try try
{ {
OnCombatPreDown.Invoke(); OnCombatPreDown.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static void OnChangeFlight_Postfix() static void OnChangeFlight_Postfix()
{ {
try try
{ {
OnFlightChange.Invoke(); OnFlightChange.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
} }
static bool OnOffsetUpdate_Prefix() static bool OnOffsetUpdate_Prefix()
{ {
try try
{ {
ms_result.m_result = false; ms_result.m_result = false;
OnIKOffsetUpdate.Invoke(ms_result); OnIKOffsetUpdate.Invoke(ms_result);
} }
catch(Exception e) catch(Exception e)
{ {
MelonLoader.MelonLogger.Error(e); MelonLoader.MelonLogger.Error(e);
} }
return !ms_result.m_result; return !ms_result.m_result;
} }
} }
} }

View file

@ -1,29 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Systems.Movement;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
class GravityInfluencer : MonoBehaviour
{
Rigidbody m_rigidBody = null;
PhysicsInfluencer m_physicsInfluencer = null;
bool m_activeGravity = true;
void Start()
{
m_rigidBody = this.GetComponent<Rigidbody>();
m_physicsInfluencer = this.GetComponent<PhysicsInfluencer>();
}
void FixedUpdate()
{
m_rigidBody.useGravity = false;
if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
}
public void SetActiveGravity(bool p_state) => m_activeGravity = p_state;
}
}

View file

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using BTKUILib.UIObjects;
using BTKUILib.UIObjects.Components;
namespace ml_prm namespace ml_prm
{ {
@ -37,83 +37,103 @@ namespace ml_prm
FallLimit FallLimit
} }
const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key";
const string c_fallLimitTooltip = "Fall limit based on impact velocity<p>Current value corresponds to drop from {0} units with default gravity</p>";
internal static readonly UiEvent OnSwitchChanged = new UiEvent(); internal static readonly UiEvent OnSwitchChanged = new UiEvent();
static List<object> ms_uiElements = null; static Page ms_page = null;
static Category ms_category = null;
static Button ms_ragdollButton = null;
static ToggleButton ms_hotkeyToggle = null;
static ToggleButton ms_gravityToggle = null;
static ToggleButton ms_pointersToggle = null;
static ToggleButton ms_ignoreLocalToggle = null;
static ToggleButton ms_combatToggle = null;
static ToggleButton ms_recoveryToggle = null;
static ToggleButton ms_slipperinessToggle = null;
static ToggleButton ms_bouncinessToggle = null;
static ToggleButton ms_viewDirectionToggle = null;
static ToggleButton ms_jumpRecoverToggle = null;
static ToggleButton ms_buoyancyToggle = null;
static ToggleButton ms_fallDamageToggle = null;
static SliderFloat ms_velocityMultiplierSlider = null;
static SliderFloat ms_movementDragSlider = null;
static SliderFloat ms_angularMovementDragSlider = null;
static SliderFloat ms_recoverDelaySlider = null;
static SliderFloat ms_fallLimitSlider = null;
static Button ms_resetButton = null;
internal static void Init() internal static void Init()
{
ms_uiElements = new List<object>();
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")); BTKUILib.QuickMenuAPI.PrepareIcon("PlayerRagdollMod", "PRM-Person", GetIconStream("person.png"));
var l_modRoot = new BTKUILib.UIObjects.Page("PlayerRagdollMod", "MainPage", true, "PRM-Person"); ms_page = new Page("PlayerRagdollMod", "MainPage", true, "PRM-Person");
l_modRoot.MenuTitle = "Player Ragdoll Mod"; ms_page.MenuTitle = "Player Ragdoll Mod";
l_modRoot.MenuSubtitle = "Become a ragdoll and change various settings for people amusement"; ms_page.MenuSubtitle = "Become a ragdoll and change various settings for people amusement";
var l_modCategory = l_modRoot.AddCategory("Settings"); ms_category = ms_page.AddCategory("Settings");
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state.").OnPress += OnSwitch; ms_ragdollButton = ms_category.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state");
ms_ragdollButton.OnPress += OnSwitch;
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.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state);
Settings.OnHotkeyKeyChanged.AddHandler(OnHotkeyKeyChanged);
ms_uiElements.Add(l_modCategory.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Settings.Hotkey)); ms_gravityToggle = ms_category.AddToggle("Use gravity", "Apply gravity to ragdoll", Settings.Gravity);
(ms_uiElements[(int)UiIndex.Hotkey] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state); ms_gravityToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Gravity, state);
ms_uiElements.Add(l_modCategory.AddToggle("Use gravity", "Apply gravity to ragdoll", Settings.Gravity)); ms_pointersToggle = ms_category.AddToggle("Pointers reaction", "React to trigger colliders with CVRPointer component of 'ragdoll' type", Settings.PointersReaction);
(ms_uiElements[(int)UiIndex.Gravity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Gravity, state); ms_pointersToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.PointersReaction, state);
ms_uiElements.Add(l_modCategory.AddToggle("Pointers reaction", "React to trigger colliders with CVRPointer component of 'ragdoll' type", Settings.PointersReaction)); ms_ignoreLocalToggle = ms_category.AddToggle("Ignore local pointers", "Ignore local avatar's CVRPointer components of 'ragdoll' type", Settings.IgnoreLocal);
(ms_uiElements[(int)UiIndex.PointersReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.PointersReaction, state); ms_ignoreLocalToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.IgnoreLocal, state);
ms_uiElements.Add(l_modCategory.AddToggle("Ignore local pointers", "Ignore local avatar's CVRPointer components of 'ragdoll' type", Settings.IgnoreLocal)); ms_combatToggle = ms_category.AddToggle("Combat reaction", "Ragdoll upon combat system death", Settings.CombatReaction);
(ms_uiElements[(int)UiIndex.IgnoreLocal] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.IgnoreLocal, state); ms_combatToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.CombatReaction, state);
ms_uiElements.Add(l_modCategory.AddToggle("Combat reaction", "Ragdoll upon combat system death", Settings.CombatReaction)); ms_recoveryToggle = ms_category.AddToggle("Auto recover", "Automatically unragdoll after set recover delay", Settings.AutoRecover);
(ms_uiElements[(int)UiIndex.CombatReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.CombatReaction, state); ms_recoveryToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.AutoRecover, state);
ms_uiElements.Add(l_modCategory.AddToggle("Auto recover", "Automatically unragdoll after set recover delay", Settings.AutoRecover)); ms_slipperinessToggle = ms_category.AddToggle("Slipperiness", "Enables/disables friction of ragdoll", Settings.Slipperiness);
(ms_uiElements[(int)UiIndex.AutoRecover] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.AutoRecover, state); ms_slipperinessToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Slipperiness, state);
ms_uiElements.Add(l_modCategory.AddToggle("Slipperiness", "Enables/disables friction of ragdoll", Settings.Slipperiness)); ms_bouncinessToggle = ms_category.AddToggle("Bounciness", "Enables/disables bounciness of ragdoll", Settings.Bounciness);
(ms_uiElements[(int)UiIndex.Slipperiness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Slipperiness, state); ms_bouncinessToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Bounciness, state);
ms_uiElements.Add(l_modCategory.AddToggle("Bounciness", "Enables/disables bounciness of ragdoll", Settings.Bounciness)); ms_viewDirectionToggle = ms_category.AddToggle("View direction velocity", "Apply velocity to camera view direction", Settings.ViewVelocity);
(ms_uiElements[(int)UiIndex.Bounciness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Bounciness, state); ms_viewDirectionToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.ViewVelocity, state);
ms_uiElements.Add(l_modCategory.AddToggle("View direction velocity", "Apply velocity to camera view direction", Settings.ViewVelocity)); ms_jumpRecoverToggle = ms_category.AddToggle("Jump recover", "Recover from ragdoll state by jumping", Settings.JumpRecover);
(ms_uiElements[(int)UiIndex.ViewVelocity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.ViewVelocity, state); ms_jumpRecoverToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.JumpRecover, state);
ms_uiElements.Add(l_modCategory.AddToggle("Jump recover", "Recover from ragdoll state by jumping", Settings.JumpRecover)); ms_buoyancyToggle = ms_category.AddToggle("Buoyancy", "Enable buoyancy in fluid volumes<p>Warning: constantly changes movement and air drag of hips, spine and chest</p>", Settings.Buoyancy);
(ms_uiElements[(int)UiIndex.JumpRecover] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.JumpRecover, state); ms_buoyancyToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Buoyancy, state);
ms_uiElements.Add(l_modCategory.AddToggle("Buoyancy", "Enable buoyancy in fluid volumes. Warning: constantly changes movement and air drag of hips, spine and chest.", Settings.Buoyancy)); ms_fallDamageToggle = ms_category.AddToggle("Fall damage", "Enable ragdoll when falling from height", Settings.FallDamage);
(ms_uiElements[(int)UiIndex.Buoyancy] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Buoyancy, state); ms_fallDamageToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FallDamage, state);
ms_uiElements.Add(l_modCategory.AddToggle("Fall damage", "Enable ragdoll when falling from height", Settings.FallDamage)); ms_velocityMultiplierSlider = ms_category.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f);
(ms_uiElements[(int)UiIndex.FallDamage] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FallDamage, state); ms_velocityMultiplierSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value);
ms_uiElements.Add(l_modCategory.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f)); ms_movementDragSlider = ms_category.AddSlider("Movement drag", "Movement resistance", Settings.MovementDrag, 0f, 50f);
(ms_uiElements[(int)UiIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value); ms_movementDragSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.MovementDrag, value);
ms_uiElements.Add(l_modCategory.AddSlider("Movement drag", "Movement resistance", Settings.MovementDrag, 0f, 50f)); ms_angularMovementDragSlider = ms_category.AddSlider("Angular movement drag", "Rotation movement resistance", Settings.AngularDrag, 0f, 50f);
(ms_uiElements[(int)UiIndex.MovementDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.MovementDrag, value); ms_angularMovementDragSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.AngularDrag, value);
ms_uiElements.Add(l_modCategory.AddSlider("Angular movement drag", "Rotation movement resistance", Settings.AngularDrag, 0f, 50f)); ms_recoverDelaySlider = ms_category.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", Settings.RecoverDelay, 1f, 10f);
(ms_uiElements[(int)UiIndex.AngularDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.AngularDrag, value); ms_recoverDelaySlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.RecoverDelay, value);
ms_uiElements.Add(l_modCategory.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", Settings.RecoverDelay, 1f, 10f)); ms_fallLimitSlider = ms_category.AddSlider("Fall limit", "", Settings.FallLimit, 4.5f, 44.5f);
(ms_uiElements[(int)UiIndex.RecoverDelay] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.RecoverDelay, value); ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(Settings.FallLimit));
ms_fallLimitSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value);
ms_uiElements.Add(l_modCategory.AddSlider("Fall limit", "Height limit for fall damage", Settings.FallLimit, 0f, 100f)); ms_resetButton = ms_category.AddButton("Reset settings", "", "Reset mod settings to default");
(ms_uiElements[(int)UiIndex.FallLimit] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value); ms_resetButton.OnPress += Reset;
l_modCategory.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset;
} }
static void OnSwitch() static void OnSwitch()
@ -128,7 +148,7 @@ namespace ml_prm
} }
} }
static void OnToggleUpdate(UiIndex p_index, bool p_state, bool p_force = false) static void OnToggleUpdate(UiIndex p_index, bool p_state)
{ {
try try
{ {
@ -182,9 +202,6 @@ namespace ml_prm
Settings.SetSetting(Settings.ModSetting.FallDamage, p_state); Settings.SetSetting(Settings.ModSetting.FallDamage, p_state);
break; break;
} }
if(p_force)
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state;
} }
catch(Exception e) catch(Exception e)
{ {
@ -192,7 +209,7 @@ namespace ml_prm
} }
} }
static void OnSliderUpdate(UiIndex p_index, float p_value, bool p_force = false) static void OnSliderUpdate(UiIndex p_index, float p_value)
{ {
try try
{ {
@ -215,12 +232,12 @@ namespace ml_prm
break; break;
case UiIndex.FallLimit: case UiIndex.FallLimit:
{
Settings.SetSetting(Settings.ModSetting.FallLimit, p_value); Settings.SetSetting(Settings.ModSetting.FallLimit, p_value);
break; ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(p_value));
}
break;
} }
if(p_force)
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value);
} }
catch(Exception e) catch(Exception e)
{ {
@ -230,23 +247,62 @@ namespace ml_prm
static void Reset() static void Reset()
{ {
OnToggleUpdate(UiIndex.Hotkey, true, true); OnToggleUpdate(UiIndex.Hotkey, true);
OnToggleUpdate(UiIndex.Gravity, true, true); ms_hotkeyToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.PointersReaction, true, true);
OnToggleUpdate(UiIndex.IgnoreLocal, true, true); OnToggleUpdate(UiIndex.Gravity, true);
OnToggleUpdate(UiIndex.CombatReaction, true, true); ms_gravityToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.AutoRecover, false, true);
OnToggleUpdate(UiIndex.Slipperiness, false, true); OnToggleUpdate(UiIndex.PointersReaction, true);
OnToggleUpdate(UiIndex.Bounciness, false, true); ms_pointersToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.ViewVelocity, false, true);
OnToggleUpdate(UiIndex.JumpRecover, false, true); OnToggleUpdate(UiIndex.IgnoreLocal, true);
OnToggleUpdate(UiIndex.Buoyancy, true, true); ms_ignoreLocalToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.FallDamage, true, true);
OnSliderUpdate(UiIndex.VelocityMultiplier, 2f, true); OnToggleUpdate(UiIndex.CombatReaction, true);
OnSliderUpdate(UiIndex.MovementDrag, 1f, true); ms_combatToggle.ToggleValue = true;
OnSliderUpdate(UiIndex.AngularDrag, 1f, true);
OnSliderUpdate(UiIndex.RecoverDelay, 3f, true); OnToggleUpdate(UiIndex.AutoRecover, false);
OnSliderUpdate(UiIndex.FallLimit, 5f, true); ms_recoveryToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.Slipperiness, false);
ms_slipperinessToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.Bounciness, false);
ms_bouncinessToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.ViewVelocity, false);
ms_viewDirectionToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.JumpRecover, false);
ms_jumpRecoverToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.Buoyancy, true);
ms_buoyancyToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.FallDamage, true);
ms_fallDamageToggle.ToggleValue = true;
OnSliderUpdate(UiIndex.VelocityMultiplier, 2f);
ms_velocityMultiplierSlider.SetSliderValue(2f);
OnSliderUpdate(UiIndex.MovementDrag, 1f);
ms_movementDragSlider.SetSliderValue(1f);
OnSliderUpdate(UiIndex.AngularDrag, 1f);
ms_angularMovementDragSlider.SetSliderValue(1f);
OnSliderUpdate(UiIndex.RecoverDelay, 3f);
ms_recoverDelaySlider.SetSliderValue(3f);
OnSliderUpdate(UiIndex.FallLimit, 9.899494f);
ms_fallLimitSlider.SetSliderValue(9.899494f);
}
static void OnHotkeyKeyChanged(UnityEngine.KeyCode p_keyCode)
{
if(ms_ragdollButton != null)
ms_hotkeyToggle.ToggleTooltip = string.Format(c_ragdollKeyTooltip, p_keyCode);
} }
static Stream GetIconStream(string p_name) static Stream GetIconStream(string p_name)
@ -255,5 +311,10 @@ namespace ml_prm
string l_assemblyName = l_assembly.GetName().Name; string l_assemblyName = l_assembly.GetName().Name;
return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
} }
static float GetDropHeight(float p_speed, float p_gravity = 9.8f)
{
return MathF.Pow(p_speed, 2f) / (p_gravity * 2f);
}
} }
} }

View file

@ -1,7 +1,7 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.8", "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.MelonOptionalDependencies("BTKUILib")] [assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]
[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)]
[assembly: MelonLoader.MelonAdditionalCredits("kafeijao, NotAKidOnSteam")] [assembly: MelonLoader.MelonAdditionalCredits("kafeijao, NotAKidOnSteam")]

View file

@ -0,0 +1,192 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.Movement;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
class RagdollBodypartHandler : MonoBehaviour, CVRTriggerVolume
{
const string c_ragdollPointerType = "ragdoll";
Rigidbody m_rigidBody = null;
public Collider collider { get; set; } = null;
PhysicsInfluencer m_physicsInfluencer = null;
bool m_shouldHaveInfluencer = false;
bool m_activeGravity = true;
// Unity events
void Awake()
{
this.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
collider = this.GetComponent<Collider>();
m_rigidBody = this.GetComponent<Rigidbody>();
if(m_rigidBody != null)
{
m_rigidBody.isKinematic = false;
m_rigidBody.detectCollisions = true;
m_rigidBody.useGravity = false;
m_rigidBody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
}
if(collider != null)
{
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.NonKinematicProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.SphereProxy.Collider, true);
BetterBetterCharacterController.Instance.IgnoreCollision(collider, true);
}
}
void Start()
{
if(m_shouldHaveInfluencer && (m_rigidBody != null) && (collider != null))
{
m_physicsInfluencer = this.gameObject.AddComponent<PhysicsInfluencer>();
m_physicsInfluencer.fluidDrag = 3f;
m_physicsInfluencer.fluidAngularDrag = 1f;
m_physicsInfluencer.enableBuoyancy = true;
m_physicsInfluencer.enableInfluence = false;
m_physicsInfluencer.forceAlignUpright = false;
float mass = m_rigidBody.mass;
m_physicsInfluencer.UpdateDensity();
m_rigidBody.mass = mass;
m_physicsInfluencer.volume = mass * 0.005f;
m_physicsInfluencer.enableLocalGravity = true;
}
if(collider != null)
{
CVRParticlePointerManager.volumes.Add(this);
CVRParticlePointerManager.UpdateParticleSystems();
}
}
void OnDestroy()
{
if(collider != null)
CVRParticlePointerManager.RemoveTrigger(collider);
}
void FixedUpdate()
{
if(m_rigidBody != null)
{
m_rigidBody.useGravity = false;
if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
}
}
void OnTriggerEnter(Collider p_col)
{
if(Settings.PointersReaction && (RagdollController.Instance != null))
{
CVRPointer l_pointer = p_col.GetComponent<CVRPointer>();
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && !IsIgnored(l_pointer.transform) && !RagdollController.Instance.IsRagdolled())
RagdollController.Instance.SwitchRagdoll();
}
}
// Arbitrary
public bool IsReady() => ((m_rigidBody != null) && (collider != null) && (!m_shouldHaveInfluencer || ((m_physicsInfluencer != null) && m_physicsInfluencer.IsReady())));
public void SetInfuencerUsage(bool p_state) => m_shouldHaveInfluencer = p_state;
public void SetColliderMaterial(PhysicMaterial p_material)
{
if(collider != null)
{
collider.sharedMaterial = p_material;
collider.material = p_material;
}
}
public void SetAsKinematic(bool p_state)
{
if(collider != null)
collider.isTrigger = p_state;
if(m_rigidBody != null)
{
m_rigidBody.isKinematic = p_state;
m_rigidBody.collisionDetectionMode = (p_state ? CollisionDetectionMode.Discrete : CollisionDetectionMode.ContinuousDynamic);
}
}
public void SetVelocity(Vector3 p_vec)
{
if(m_rigidBody != null)
m_rigidBody.velocity = p_vec;
}
public void SetAngularVelocity(Vector3 p_vec)
{
if(m_rigidBody != null)
m_rigidBody.angularVelocity = p_vec;
}
public void SetActiveGravity(bool p_state)
{
m_activeGravity = p_state;
if(m_physicsInfluencer != null)
m_physicsInfluencer.enabled = m_activeGravity;
}
public void SetDrag(float p_value)
{
if(m_rigidBody != null)
{
m_rigidBody.drag = p_value;
m_rigidBody.WakeUp();
}
if(m_physicsInfluencer != null)
m_physicsInfluencer.airDrag = p_value;
}
public void SetAngularDrag(float p_value)
{
if(m_rigidBody != null)
{
m_rigidBody.angularDrag = p_value;
m_rigidBody.WakeUp();
}
if(m_physicsInfluencer != null)
m_physicsInfluencer.airAngularDrag = p_value;
}
public void SetBuoyancy(bool p_state)
{
if(m_physicsInfluencer != null)
m_physicsInfluencer.enableInfluence = p_state;
}
public void ClearFluidVolumes()
{
if(m_physicsInfluencer != null)
m_physicsInfluencer.ClearFluidVolumes();
}
static bool IsIgnored(Transform p_transform)
{
return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform));
}
// CVRTriggerVolume
public void TriggerEnter(CVRPointer pointer)
{
if(Settings.PointersReaction && (RagdollController.Instance != null))
{
if((pointer != null) && (pointer.type == c_ragdollPointerType) && !IsIgnored(pointer.transform) && !RagdollController.Instance.IsRagdolled())
RagdollController.Instance.SwitchRagdoll();
}
}
public void TriggerExit(CVRPointer pointer) { }
}
}

View file

@ -27,15 +27,12 @@ namespace ml_prm
bool m_enabled = false; bool m_enabled = false;
bool m_forcedSwitch = false; bool m_forcedSwitch = false;
readonly List<Rigidbody> m_rigidBodies = null;
readonly List<Collider> m_colliders = null;
Transform m_puppetRoot = null; Transform m_puppetRoot = null;
Transform m_puppet = null; Transform m_puppet = null;
BipedRagdollReferences m_puppetReferences; BipedRagdollReferences m_puppetReferences;
readonly List<RagdollBodypartHandler> m_ragdollBodyHandlers = null;
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null; readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null; readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null;
readonly List<PhysicsInfluencer> m_physicsInfluencers = null;
readonly List<GravityInfluencer> m_gravityInfluencers = null;
bool m_avatarReady = false; bool m_avatarReady = false;
Coroutine m_initCoroutine = null; Coroutine m_initCoroutine = null;
@ -44,8 +41,7 @@ namespace ml_prm
Vector3 m_ragdollLastPos = Vector3.zero; Vector3 m_ragdollLastPos = Vector3.zero;
bool m_wasSwimming = false; bool m_wasSwimming = false;
RagdollToggle m_avatarRagdollToggle = null; RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor
RagdollTrigger m_ragdollTrigger = null;
AvatarBoolParameter m_ragdolledParameter = null; AvatarBoolParameter m_ragdolledParameter = null;
PhysicMaterial m_physicsMaterial = null; PhysicMaterial m_physicsMaterial = null;
@ -54,24 +50,25 @@ namespace ml_prm
float m_downTime = float.MinValue; float m_downTime = float.MinValue;
bool m_inAir = false; bool m_inAir = false;
float m_inAirDistance = 0f;
internal RagdollController() internal RagdollController()
{ {
m_rigidBodies = new List<Rigidbody>(); m_ragdollBodyHandlers = new List<RagdollBodypartHandler>();
m_colliders = new List<Collider>();
m_boneLinks = new List<System.Tuple<Transform, Transform>>(); m_boneLinks = new List<System.Tuple<Transform, Transform>>();
m_jointAnchors = new List<System.Tuple<CharacterJoint, Vector3>>(); m_jointAnchors = new List<System.Tuple<CharacterJoint, Vector3>>();
m_physicsInfluencers = new List<PhysicsInfluencer>();
m_gravityInfluencers = new List<GravityInfluencer>();
} }
// Unity events // Unity events
void Awake()
{
if((Instance != null) && (Instance != this))
Object.Destroy(this);
else
Instance = this;
}
void Start() void Start()
{ {
if(Instance == null)
Instance = this;
m_physicsMaterial = new PhysicMaterial("Ragdoll"); m_physicsMaterial = new PhysicMaterial("Ragdoll");
m_physicsMaterial.dynamicFriction = c_defaultFriction; m_physicsMaterial.dynamicFriction = c_defaultFriction;
m_physicsMaterial.staticFriction = c_defaultFriction; m_physicsMaterial.staticFriction = c_defaultFriction;
@ -84,9 +81,6 @@ namespace ml_prm
m_puppetRoot.localPosition = Vector3.zero; m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity; m_puppetRoot.localRotation = Quaternion.identity;
m_ragdollTrigger = BetterBetterCharacterController.Instance.NonKinematicProxy.gameObject.AddComponent<RagdollTrigger>();
m_ragdollTrigger.enabled = false;
Settings.OnMovementDragChanged.AddHandler(this.OnMovementDragChanged); Settings.OnMovementDragChanged.AddHandler(this.OnMovementDragChanged);
Settings.OnAngularDragChanged.AddHandler(this.OnAngularDragChanged); Settings.OnAngularDragChanged.AddHandler(this.OnAngularDragChanged);
Settings.OnGravityChanged.AddHandler(this.OnGravityChanged); Settings.OnGravityChanged.AddHandler(this.OnGravityChanged);
@ -125,17 +119,11 @@ namespace ml_prm
m_puppetRoot = null; m_puppetRoot = null;
m_puppet = null; m_puppet = null;
m_rigidBodies.Clear(); m_ragdollBodyHandlers.Clear();
m_colliders.Clear();
m_boneLinks.Clear(); m_boneLinks.Clear();
m_jointAnchors.Clear(); m_jointAnchors.Clear();
m_physicsInfluencers.Clear();
m_avatarRagdollToggle = null; m_avatarRagdollToggle = null;
if(m_ragdollTrigger != null)
Object.Destroy(m_ragdollTrigger);
m_ragdollTrigger = null;
if(m_physicsMaterial != null) if(m_physicsMaterial != null)
Object.Destroy(m_physicsMaterial); Object.Destroy(m_physicsMaterial);
m_physicsMaterial = null; m_physicsMaterial = null;
@ -170,33 +158,23 @@ namespace ml_prm
{ {
bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded(); bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded();
bool l_inWater = BetterBetterCharacterController.Instance.IsInWater(); bool l_inWater = BetterBetterCharacterController.Instance.IsInWater();
if(m_inAir && l_grounded && !l_inWater && (m_inAirDistance > Settings.FallLimit)) if(m_inAir && l_grounded && !l_inWater && (m_velocity.magnitude >= Settings.FallLimit))
{
m_inAirDistance = 0f;
SwitchRagdoll(); SwitchRagdoll();
}
m_inAir = !(l_grounded || l_inWater); m_inAir = !(l_grounded || l_inWater);
if(!m_inAir)
m_inAirDistance = 0f;
} }
if(m_avatarReady && m_enabled) if(m_avatarReady && m_enabled)
{ {
m_inAirDistance = 0f;
BodySystem.TrackingPositionWeight = 0f; BodySystem.TrackingPositionWeight = 0f;
BetterBetterCharacterController.Instance.PauseGroundConstraint();
BetterBetterCharacterController.Instance.ResetAllForces();
} }
if(m_avatarReady && !m_enabled) if(m_avatarReady && !m_enabled)
{ {
Vector3 l_pos = PlayerSetup.Instance.transform.position; Vector3 l_pos = PlayerSetup.Instance.transform.position;
m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f; m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f;
if(m_inAir)
{
m_inAirDistance += (Quaternion.Inverse(PlayerSetup.Instance.transform.rotation) * (m_lastPosition - l_pos)).y;
m_inAirDistance = Mathf.Clamp(m_inAirDistance, 0f, float.MaxValue);
}
m_lastPosition = l_pos; m_lastPosition = l_pos;
if(!m_reachedGround && BetterBetterCharacterController.Instance.IsOnGround()) if(!m_reachedGround && BetterBetterCharacterController.Instance.IsOnGround())
@ -220,9 +198,6 @@ namespace ml_prm
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_ragdollTrigger != null) && m_ragdollTrigger.GetStateWithReset() && m_avatarReady && !m_enabled && Settings.PointersReaction)
SwitchRagdoll();
if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.IsAnyMenuOpen) if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.IsAnyMenuOpen)
SwitchRagdoll(); SwitchRagdoll();
@ -277,31 +252,21 @@ namespace ml_prm
Object.Destroy(m_puppet.gameObject); Object.Destroy(m_puppet.gameObject);
m_puppet = null; m_puppet = null;
if(m_ragdollTrigger != null)
{
m_ragdollTrigger.GetStateWithReset();
m_ragdollTrigger.enabled = false;
}
m_vrIK = null; m_vrIK = null;
m_applyHipsPosition = false; m_applyHipsPosition = false;
m_enabled = false; m_enabled = false;
m_avatarReady = false; m_avatarReady = false;
m_avatarRagdollToggle = null; m_avatarRagdollToggle = null;
m_ragdolledParameter = null; m_ragdolledParameter = null;
m_rigidBodies.Clear();
m_colliders.Clear();
m_puppetReferences = new BipedRagdollReferences(); m_puppetReferences = new BipedRagdollReferences();
m_ragdollBodyHandlers.Clear();
m_boneLinks.Clear(); m_boneLinks.Clear();
m_jointAnchors.Clear(); m_jointAnchors.Clear();
m_physicsInfluencers.Clear();
m_gravityInfluencers.Clear();
m_reachedGround = true; m_reachedGround = true;
m_groundedTime = 0f; m_groundedTime = 0f;
m_downTime = float.MinValue; m_downTime = float.MinValue;
m_puppetRoot.localScale = Vector3.one; m_puppetRoot.localScale = Vector3.one;
m_inAir = false; m_inAir = false;
m_inAirDistance = 0f;
m_wasSwimming = false; m_wasSwimming = false;
} }
@ -353,26 +318,11 @@ namespace ml_prm
Transform[] l_puppetTransforms = m_puppetReferences.GetRagdollTransforms(); Transform[] l_puppetTransforms = m_puppetReferences.GetRagdollTransforms();
Transform[] l_avatarTransforms = l_avatarReferences.GetRagdollTransforms(); Transform[] l_avatarTransforms = l_avatarReferences.GetRagdollTransforms();
Transform[] l_influencedTransforms = new Transform[] { m_puppetReferences.hips, m_puppetReferences.spine, m_puppetReferences.chest };
for(int i = 0; i < l_puppetTransforms.Length; i++) for(int i = 0; i < l_puppetTransforms.Length; i++)
{ {
if(l_puppetTransforms[i] != null) if(l_puppetTransforms[i] != null)
{ {
Rigidbody l_body = l_puppetTransforms[i].GetComponent<Rigidbody>();
if(l_body != null)
{
m_rigidBodies.Add(l_body);
l_body.isKinematic = true;
l_body.angularDrag = Settings.AngularDrag;
l_body.drag = (WorldHandler.IsSafeWorld() ? Settings.MovementDrag : 1f);
l_body.useGravity = false;
l_body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
l_body.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
GravityInfluencer l_gravInfluencer = l_body.gameObject.AddComponent<GravityInfluencer>();
l_gravInfluencer.SetActiveGravity((!WorldHandler.IsSafeWorld() || Settings.Gravity));
m_gravityInfluencers.Add(l_gravInfluencer);
}
CharacterJoint l_joint = l_puppetTransforms[i].GetComponent<CharacterJoint>(); CharacterJoint l_joint = l_puppetTransforms[i].GetComponent<CharacterJoint>();
if(l_joint != null) if(l_joint != null)
{ {
@ -381,37 +331,13 @@ namespace ml_prm
m_jointAnchors.Add(System.Tuple.Create(l_joint, l_joint.connectedAnchor)); m_jointAnchors.Add(System.Tuple.Create(l_joint, l_joint.connectedAnchor));
} }
Rigidbody l_body = l_puppetTransforms[i].GetComponent<Rigidbody>();
Collider l_collider = l_puppetTransforms[i].GetComponent<Collider>(); Collider l_collider = l_puppetTransforms[i].GetComponent<Collider>();
if(l_collider != null) if((l_body != null) && (l_collider != null))
{ {
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.Collider, true); RagdollBodypartHandler l_handler = l_puppetTransforms[i].gameObject.AddComponent<RagdollBodypartHandler>();
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, true); l_handler.SetInfuencerUsage(Utils.IsInEnumeration(l_puppetTransforms[i], l_influencedTransforms));
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.NonKinematicProxy.Collider, true); m_ragdollBodyHandlers.Add(l_handler);
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.SphereProxy.Collider, true);
BetterBetterCharacterController.Instance.IgnoreCollision(l_collider, true);
l_collider.sharedMaterial = m_physicsMaterial;
l_collider.material = m_physicsMaterial;
m_colliders.Add(l_collider);
}
if((l_body != null) && (l_collider != null) && (l_puppetTransforms[i] == m_puppetReferences.hips || l_puppetTransforms[i] == m_puppetReferences.spine || l_puppetTransforms[i] == m_puppetReferences.chest))
{
PhysicsInfluencer l_physicsInfluencer = l_puppetTransforms[i].gameObject.AddComponent<PhysicsInfluencer>();
l_physicsInfluencer.airDrag = (WorldHandler.IsSafeWorld() ? Settings.MovementDrag : 1f);
l_physicsInfluencer.airAngularDrag = Settings.AngularDrag;
l_physicsInfluencer.fluidDrag = 3f;
l_physicsInfluencer.fluidAngularDrag = 1f;
l_physicsInfluencer.enableBuoyancy = true;
l_physicsInfluencer.enableInfluence = false;
l_physicsInfluencer.forceAlignUpright = false;
float mass = l_body.mass;
l_physicsInfluencer.UpdateDensity();
l_body.mass = mass;
l_physicsInfluencer.volume = mass * 0.005f;
l_physicsInfluencer.enableLocalGravity = true;
m_physicsInfluencers.Add(l_physicsInfluencer);
} }
if(l_avatarTransforms[i] != null) if(l_avatarTransforms[i] != null)
@ -422,7 +348,6 @@ namespace ml_prm
// And return back // And return back
m_puppetRoot.localPosition = Vector3.zero; m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity; m_puppetRoot.localRotation = Quaternion.identity;
m_puppetRoot.gameObject.SetActive(true);
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>(); m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
if(m_vrIK != null) if(m_vrIK != null)
@ -431,25 +356,28 @@ namespace ml_prm
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true); m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true);
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager); m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
m_initCoroutine = StartCoroutine(WaitForPhysicsInfluencers()); m_initCoroutine = StartCoroutine(WaitForBodyHandlers());
} }
} }
IEnumerator WaitForPhysicsInfluencers() IEnumerator WaitForBodyHandlers()
{ {
while(!m_physicsInfluencers.TrueForAll(p => p.IsReady())) while(!m_ragdollBodyHandlers.TrueForAll(p => p.IsReady()))
yield return null; yield return null;
m_puppetRoot.gameObject.SetActive(false); foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{
l_handler.SetAsKinematic(true);
l_handler.SetColliderMaterial(m_physicsMaterial);
}
m_ragdollTrigger.enabled = true;
m_avatarReady = true; m_avatarReady = true;
m_initCoroutine = null; m_initCoroutine = null;
OnGravityChanged(Settings.Gravity);
OnBuoyancyChanged(Settings.Buoyancy);
OnMovementDragChanged(Settings.MovementDrag); OnMovementDragChanged(Settings.MovementDrag);
OnAngularDragChanged(Settings.AngularDrag); OnAngularDragChanged(Settings.AngularDrag);
OnGravityChanged(Settings.Gravity);
OnBuoyancyChanged(Settings.Buoyancy);
} }
void OnAvatarPreReuse() void OnAvatarPreReuse()
@ -573,28 +501,16 @@ namespace ml_prm
if(m_avatarReady) if(m_avatarReady)
{ {
float l_drag = (WorldHandler.IsSafeWorld() ? p_value : 1f); float l_drag = (WorldHandler.IsSafeWorld() ? p_value : 1f);
foreach(Rigidbody l_body in m_rigidBodies) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{ l_handler.SetDrag(l_drag);
l_body.drag = l_drag;
if(m_enabled)
l_body.WakeUp();
}
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.airDrag = l_drag;
} }
} }
void OnAngularDragChanged(float p_value) void OnAngularDragChanged(float p_value)
{ {
if(m_avatarReady) if(m_avatarReady)
{ {
foreach(Rigidbody l_body in m_rigidBodies) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{ l_handler.SetAngularDrag(p_value);
l_body.angularDrag = p_value;
if(m_enabled)
l_body.WakeUp();
}
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.airAngularDrag = p_value;
} }
} }
void OnGravityChanged(bool p_state) void OnGravityChanged(bool p_state)
@ -602,10 +518,8 @@ namespace ml_prm
if(m_avatarReady) if(m_avatarReady)
{ {
bool l_gravity = (!WorldHandler.IsSafeWorld() || p_state); bool l_gravity = (!WorldHandler.IsSafeWorld() || p_state);
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_influencer.enabled = l_gravity; l_handler.SetActiveGravity(l_gravity);
foreach(GravityInfluencer l_influencer in m_gravityInfluencers)
l_influencer.SetActiveGravity(l_gravity);
if(!l_gravity) if(!l_gravity)
{ {
@ -632,8 +546,8 @@ namespace ml_prm
if(m_avatarReady) if(m_avatarReady)
{ {
bool l_buoyancy = (!WorldHandler.IsSafeWorld() || p_state); bool l_buoyancy = (!WorldHandler.IsSafeWorld() || p_state);
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_influencer.enableInfluence = l_buoyancy; l_handler.SetBuoyancy(l_buoyancy);
if(!l_buoyancy) if(!l_buoyancy)
{ {
@ -645,7 +559,6 @@ namespace ml_prm
void OnFallDamageChanged(bool p_state) void OnFallDamageChanged(bool p_state)
{ {
m_inAir = false; m_inAir = false;
m_inAirDistance = 0f;
} }
// Arbitrary // Arbitrary
@ -663,6 +576,8 @@ namespace ml_prm
BetterBetterCharacterController.Instance.ChangeFlight(false, true); BetterBetterCharacterController.Instance.ChangeFlight(false, true);
BetterBetterCharacterController.Instance.SetImmobilized(true); BetterBetterCharacterController.Instance.SetImmobilized(true);
BetterBetterCharacterController.Instance.ClearFluidVolumes(); BetterBetterCharacterController.Instance.ClearFluidVolumes();
BetterBetterCharacterController.Instance.ResetAllForces();
BetterBetterCharacterController.Instance.PauseGroundConstraint();
BodySystem.TrackingPositionWeight = 0f; BodySystem.TrackingPositionWeight = 0f;
m_applyHipsPosition = IKSystem.Instance.applyOriginalHipPosition; m_applyHipsPosition = IKSystem.Instance.applyOriginalHipPosition;
IKSystem.Instance.applyOriginalHipPosition = true; IKSystem.Instance.applyOriginalHipPosition = true;
@ -678,10 +593,11 @@ namespace ml_prm
m_groundedTime = 0f; m_groundedTime = 0f;
} }
m_puppetRoot.gameObject.SetActive(true); foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_handler.SetAsKinematic(false);
foreach(Rigidbody l_body in m_rigidBodies) m_puppetRoot.gameObject.SetActive(false); //
l_body.isKinematic = false; m_puppetRoot.gameObject.SetActive(true); // Resets rigidbodies and joints inner physics states
Vector3 l_velocity = Vector3.ClampMagnitude(m_velocity * (WorldHandler.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldHandler.GetMovementLimit()); Vector3 l_velocity = Vector3.ClampMagnitude(m_velocity * (WorldHandler.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldHandler.GetMovementLimit());
if(Settings.ViewVelocity && WorldHandler.IsSafeWorld()) if(Settings.ViewVelocity && WorldHandler.IsSafeWorld())
@ -690,10 +606,10 @@ namespace ml_prm
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag; l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
} }
foreach(Rigidbody l_body in m_rigidBodies) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{ {
l_body.velocity = l_velocity; l_handler.SetVelocity(l_velocity);
l_body.angularVelocity = Vector3.zero; l_handler.SetAngularVelocity(Vector3.zero);
} }
m_ragdollLastPos = m_puppetReferences.hips.position; m_ragdollLastPos = m_puppetReferences.hips.position;
@ -723,15 +639,14 @@ namespace ml_prm
m_ragdolledParameter.SetValue(false); m_ragdolledParameter.SetValue(false);
m_puppetRoot.gameObject.SetActive(false);
m_puppetRoot.localPosition = Vector3.zero; m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity; m_puppetRoot.localRotation = Quaternion.identity;
foreach(Rigidbody l_body in m_rigidBodies) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_body.isKinematic = true; {
l_handler.SetAsKinematic(true);
foreach(PhysicsInfluencer l_physicsInfluencer in m_physicsInfluencers) l_handler.ClearFluidVolumes();
l_physicsInfluencer.ClearFluidVolumes(); }
m_lastPosition = PlayerSetup.Instance.transform.position; m_lastPosition = PlayerSetup.Instance.transform.position;
m_velocity = Vector3.zero; m_velocity = Vector3.zero;
@ -762,7 +677,6 @@ namespace ml_prm
} }
m_inAir = false; m_inAir = false;
m_inAirDistance = 0f;
} }
static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name) static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)

View file

@ -1,108 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
class RagdollTrigger : MonoBehaviour
{
const string c_ragdollPointerType = "ragdoll";
Collider m_collider = null;
Collider m_lastColliderTrigger = null;
ParticleSystem m_lastParticleSystemTrigger = null;
bool m_triggered = false;
void Start()
{
m_collider = this.GetComponent<Collider>();
CVRParticlePointerManager.volumes.Add(new RagdollTriggerVolume(m_collider, this));
CVRParticlePointerManager.UpdateParticleSystems();
}
void OnDestroy()
{
if(m_collider != null)
CVRParticlePointerManager.RemoveTrigger(m_collider);
m_collider = null;
m_lastColliderTrigger = null;
m_lastParticleSystemTrigger = null;
}
void Update()
{
if(!ReferenceEquals(m_lastColliderTrigger, null))
{
if(m_lastColliderTrigger != null)
{
if(!m_collider.bounds.Intersects(m_lastColliderTrigger.bounds))
m_lastColliderTrigger = null;
}
else
m_lastColliderTrigger = null;
}
if(!ReferenceEquals(m_lastParticleSystemTrigger, null))
{
if(m_lastParticleSystemTrigger != null)
{
if(m_lastParticleSystemTrigger.particleCount == 0)
m_lastParticleSystemTrigger = null;
}
else
m_lastParticleSystemTrigger = null;
}
}
void OnTriggerEnter(Collider p_other)
{
CVRPointer l_pointer = p_other.GetComponent<CVRPointer>();
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && !IsIgnored(l_pointer.transform) && (m_lastColliderTrigger != p_other))
{
m_lastColliderTrigger = p_other;
m_triggered = true;
}
}
void OnTriggerExit(Collider p_other)
{
if(m_lastColliderTrigger == p_other)
m_lastColliderTrigger = null;
}
public void OnPointerParticleEnter(CVRPointer p_pointer)
{
if(!this.gameObject.activeInHierarchy)
return;
if((p_pointer.type == c_ragdollPointerType) && !IsIgnored(p_pointer.transform) && (m_lastParticleSystemTrigger != p_pointer.particleSystem))
{
m_lastParticleSystemTrigger = p_pointer.particleSystem;
m_triggered = true;
}
}
public void OnPointerParticleExit(CVRPointer p_pointer)
{
// This seems to be very unreliable, and it's causing weird behavior
// if (!gameObject.activeInHierarchy) return;
// if(m_lastParticleSystemTrigger == p_pointer.particleSystem)
// m_lastParticleSystemTrigger = null;
}
public bool GetStateWithReset()
{
bool l_state = m_triggered;
m_triggered = false;
return l_state;
}
static bool IsIgnored(Transform p_transform)
{
return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform));
}
}
}

View file

@ -1,22 +0,0 @@
using ABI_RC.Core.Savior;
using ABI.CCK.Components;
using UnityEngine;
namespace ml_prm
{
class RagdollTriggerVolume : CVRTriggerVolume
{
readonly RagdollTrigger m_trigger = null;
public Collider collider { get; set; }
internal RagdollTriggerVolume(Collider p_collider, RagdollTrigger p_trigger)
{
collider = p_collider;
m_trigger = p_trigger;
}
public void TriggerEnter(CVRPointer pointer) => m_trigger.OnPointerParticleEnter(pointer);
public void TriggerExit(CVRPointer pointer) => m_trigger.OnPointerParticleExit(pointer);
}
}

View file

@ -53,7 +53,7 @@ namespace ml_prm
public static bool JumpRecover { get; private set; } = false; public static bool JumpRecover { get; private set; } = false;
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; } = 5f; public static float FallLimit { get; private set; } = 9.899494f;
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>();
@ -122,7 +122,7 @@ namespace ml_prm
JumpRecover = (bool)ms_entries[(int)ModSetting.JumpRecover].BoxedValue; JumpRecover = (bool)ms_entries[(int)ModSetting.JumpRecover].BoxedValue;
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, 0f, 100f); FallLimit = Mathf.Clamp((float)ms_entries[(int)ModSetting.FallLimit].BoxedValue, 4.5f, 44.5f);
} }
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue) static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)

View file

@ -6,6 +6,7 @@ using ABI_RC.Systems.Movement;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using UnityEngine; using UnityEngine;
using System.Linq;
namespace ml_prm namespace ml_prm
{ {
@ -40,5 +41,7 @@ namespace ml_prm
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
} }
public static bool IsInEnumeration(object p_obj, object[] p_enumeration) => p_enumeration.Contains(p_obj);
} }
} }

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.7</Version> <Version>1.1.8</Version>
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>None</Company> <Company>None</Company>
<Product>PlayerRagdollMod</Product> <Product>PlayerRagdollMod</Product>