using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
using System;
using AOT;
#if UNITY_IOS
using UnityEngine.iOS;
#endif
namespace MoreMountains.NiceVibrations
{
///
/// This class handles all iOS haptics specific calls for devices that support the CoreHaptics API (post iOS 13)
///
public static class MMNViOSCoreHaptics
{
public static event Action OnHapticPatternStopped;
public static event Action OnHapticPatternError;
public static event Action OnHapticPatternReset;
private static float _initialContinuousIntensity;
private static float _initialContinuousSharpness;
#if UNITY_IOS && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern bool MMNViOS_CoreHapticsSupported();
[DllImport("__Internal")]
private static extern void MMNViOS_CreateEngine();
[DllImport("__Internal")]
private static extern void MMNViOS_StopEngine();
[DllImport("__Internal")]
private static extern void MMNViOS_PlayTransientHapticPattern(float intensity, float sharpness, bool threaded);
[DllImport("__Internal")]
private static extern void MMNViOS_PlayContinuousHapticPattern(float intensity, float sharpness, float duration, bool threaded);
[DllImport("__Internal")]
private static extern void MMNViOS_UpdateContinuousHapticPattern(float intensity, float sharpness, bool threaded);
[DllImport("__Internal")]
private static extern void MMNViOS_StopContinuousHaptic();
[DllImport("__Internal")]
private static extern void MMNViOS_PlayCoreHapticsFromJSON(string jsonString, bool threaded);
[DllImport("__Internal")]
private static extern void MMNViOS_CoreHapticsRegisterHapticEngineFinishedCallback(Action callback);
[DllImport("__Internal")]
private static extern void MMNViOS_CoreHapticsRegisterHapticEngineErrorCallback(Action callback);
[DllImport("__Internal")]
private static extern void MMNViOS_CoreHapticsRegisterHapticEngineResetCallback(Action callback);
[DllImport("__Internal")]
private static extern void MMNViOS_CoreHapticsSetDebugMode(bool status);
#else
private static bool MMNViOS_CoreHapticsSupported() { return false; }
private static void MMNViOS_CoreHapticsSetDebugMode(bool status) { }
private static void MMNViOS_CreateEngine() { }
private static void MMNViOS_StopEngine() { }
private static void MMNViOS_PlayTransientHapticPattern(float intensity, float sharpness, bool threaded) { }
private static void MMNViOS_PlayContinuousHapticPattern(float intensity, float sharpness, float duration, bool threaded) { }
private static void MMNViOS_UpdateContinuousHapticPattern(float intensity, float sharpness, bool threaded) { }
private static void MMNViOS_StopContinuousHaptic() { }
private static void MMNViOS_PlayCoreHapticsFromJSON(string jsonString, bool threaded) { }
private static void MMNViOS_CoreHapticsRegisterHapticEngineFinishedCallback(Action callback) { }
private static void MMNViOS_CoreHapticsRegisterHapticEngineErrorCallback(Action callback) { }
private static void MMNViOS_CoreHapticsRegisterHapticEngineResetCallback(Action callback) { }
#endif
///
/// On construction we initialize our haptic engine
///
static MMNViOSCoreHaptics()
{
MMNViOS_CoreHapticsRegisterHapticEngineFinishedCallback(HapticStoppedCallback);
MMNViOS_CoreHapticsRegisterHapticEngineErrorCallback(HapticsErrorCallback);
MMNViOS_CoreHapticsRegisterHapticEngineResetCallback(HapticsResetCallback);
}
///
/// Plays a core haptics pattern from a JSON string that matches the AHAP format
///
///
public static void PlayCoreHapticsFromJSON(string jsonString, bool threaded = false)
{
MMNViOS_PlayCoreHapticsFromJSON(jsonString, threaded);
}
///
/// Plays a transient haptic pattern of the specified intensity and sharpness.
/// Transient haptics are very short haptic patterns.
///
///
///
public static void PlayTransientHapticPattern(float intensity, float sharpness, bool threaded = false)
{
MMNViOS_PlayTransientHapticPattern(intensity, sharpness, threaded);
}
///
/// Plays a continuous haptic at the specified intensity and sharpness for the specified duration
/// The coroutineMonobehaviour parameter is optional, only send that if you intend to raise this specific continuous pattern's intensity higher than its
/// initial value
///
///
///
///
///
public static void PlayContinuousHapticPattern(float intensity, float sharpness,
float duration, MonoBehaviour coroutineMonobehaviour = null, bool threaded = false)
{
if (intensity < 0.01f)
{
intensity = 0.01f;
}
_initialContinuousIntensity = intensity;
_initialContinuousSharpness = sharpness;
if (coroutineMonobehaviour != null)
{
_initialContinuousIntensity = 1f;
MMNViOS_PlayContinuousHapticPattern(1f, sharpness, duration, threaded);
coroutineMonobehaviour.StartCoroutine(ContinuousHapticPatternCoroutine(intensity, sharpness, threaded));
}
else
{
MMNViOS_PlayContinuousHapticPattern(intensity, sharpness, duration, threaded);
}
}
///
/// This coroutine waits for a frame and returns intensity to its normal value
///
///
///
///
public static IEnumerator ContinuousHapticPatternCoroutine(float intensity, float sharpness, bool threaded = false)
{
yield return null;
MMNViOS_UpdateContinuousHapticPattern(intensity, sharpness, threaded);
}
///
/// This method lets you update the intensity and sharpness of a continuous haptics as it's playing.
/// Note that this one is a direct implementation of Apple's native method that serves that same purpose, and
/// the way it works can be confusing, as instead of just setting the value, it multiplies and adds like so :
/// Sending a dynamic parameter for intensity multiplies the original pattern’s event intensity by the dynamic parameter value.
/// Sending a dynamic parameter for sharpness adds the dynamic parameter value to the original pattern’s event sharpness.
/// If you'd rather not have to do weird maths to just set two values, you can use
/// the UpdateContinuousHapticPatternRational method, which will handle that for you.
///
///
///
public static void UpdateContinuousHapticPattern(float intensity, float sharpness, bool threaded = false)
{
MMNViOS_UpdateContinuousHapticPattern(intensity, sharpness, threaded);
}
///
/// This method lets you update the intensity and sharpness of a continuous haptics as it's playing.
/// It simply sets the intensity and sharpness values to the ones set in parameters
/// Just note that due to limitations in Apple's implementation, the intensity can't go higher than its initial value.
/// The only way to bypass that is to pass a monobehaviour to PlayContinuousHapticPattern when calling it
///
///
///
public static void UpdateContinuousHapticPatternRational(float intensity, float sharpness, bool threaded = false)
{
if (_initialContinuousIntensity < 0.01f)
{
_initialContinuousIntensity = 0.01f;
}
float newIntensity = intensity / _initialContinuousIntensity;
float newSharpness = sharpness - _initialContinuousSharpness;
MMNViOS_UpdateContinuousHapticPattern(newIntensity, newSharpness, threaded);
}
///
/// Stops all running or continuous haptic patterns
///
public static void StopHapticPatterns()
{
MMNViOS_StopContinuousHaptic();
}
///
/// Stops the haptic engine entirely, cutting short any AHAP or transient that may have been playing
///
public static void CreateEngine()
{
MMNViOS_CreateEngine();
}
///
/// Stops the haptic engine entirely, cutting short any AHAP or transient that may have been playing
///
public static void StopEngine()
{
MMNViOS_StopEngine();
}
///
/// Sets the debug mode to true or false.
/// While debug mode is active, pretty much every haptic call will output a log in the console.
/// Useful when debugging without a device
///
///
public static void SetDebugMode(bool newStatus)
{
MMNViOS_CoreHapticsSetDebugMode(newStatus);
}
///
/// Returns true if CoreHaptics are supported, false otherwise
///
///
public static bool CoreHapticsSupported()
{
return MMNViOS_CoreHapticsSupported();
}
///
/// Triggers the haptics stopped callback
///
#if UNITY_IOS
[MonoPInvokeCallback(typeof(Action))]
#endif
private static void HapticStoppedCallback()
{
OnHapticPatternStopped?.Invoke();
}
///
/// Triggers the haptics error callback
///
#if UNITY_IOS
[MonoPInvokeCallback(typeof(Action))]
#endif
private static void HapticsErrorCallback()
{
OnHapticPatternError?.Invoke();
}
///
/// Triggers the haptics reset callback
///
#if UNITY_IOS
[MonoPInvokeCallback(typeof(Action))]
#endif
private static void HapticsResetCallback()
{
OnHapticPatternReset?.Invoke();
}
}
}