diff --git a/Assets/Plugins/Android.meta b/Assets/Plugins/Android.meta new file mode 100644 index 0000000..75d12b1 --- /dev/null +++ b/Assets/Plugins/Android.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9390e14b79696426d8527e368308b77c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/libs.meta b/Assets/Plugins/Android/libs.meta new file mode 100644 index 0000000..c23b029 --- /dev/null +++ b/Assets/Plugins/Android/libs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c8e190729c262425ab13ea81b5b478c6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/libs/LofeltHaptics.aar b/Assets/Plugins/Android/libs/LofeltHaptics.aar new file mode 100644 index 0000000..5c2bd4e Binary files /dev/null and b/Assets/Plugins/Android/libs/LofeltHaptics.aar differ diff --git a/Assets/Plugins/Android/libs/LofeltHaptics.aar.meta b/Assets/Plugins/Android/libs/LofeltHaptics.aar.meta new file mode 100644 index 0000000..6dc46a5 --- /dev/null +++ b/Assets/Plugins/Android/libs/LofeltHaptics.aar.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 4052800b132124e29b9627e77b348b41 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Windows.meta b/Assets/Plugins/Windows.meta new file mode 100644 index 0000000..934e753 --- /dev/null +++ b/Assets/Plugins/Windows.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 04babe37531df1741bce773dd20ddca0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Windows/x64.meta b/Assets/Plugins/Windows/x64.meta new file mode 100644 index 0000000..f6a565c --- /dev/null +++ b/Assets/Plugins/Windows/x64.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1cfa7fc0db963a4897d26b3d50d11ec +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Windows/x64/nice_vibrations_editor_plugin.dll b/Assets/Plugins/Windows/x64/nice_vibrations_editor_plugin.dll new file mode 100644 index 0000000..97a5b45 Binary files /dev/null and b/Assets/Plugins/Windows/x64/nice_vibrations_editor_plugin.dll differ diff --git a/Assets/Plugins/Windows/x64/nice_vibrations_editor_plugin.dll.meta b/Assets/Plugins/Windows/x64/nice_vibrations_editor_plugin.dll.meta new file mode 100644 index 0000000..57fdade --- /dev/null +++ b/Assets/Plugins/Windows/x64/nice_vibrations_editor_plugin.dll.meta @@ -0,0 +1,80 @@ +fileFormatVersion: 2 +guid: b177fc310544d6a4c94b26e23d9b31d1 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude WindowsStoreApps: 1 + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: x86_64 + DefaultValueInitialized: true + OS: Windows + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + WebGL: WebGL + second: + enabled: 0 + settings: {} + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: X64 + DontProcess: false + PlaceholderPath: + SDK: AnySDK + ScriptingBackend: AnyScriptingBackend + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS.meta b/Assets/Plugins/iOS.meta new file mode 100644 index 0000000..f20b5c7 --- /dev/null +++ b/Assets/Plugins/iOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3cc8ce9203c4a4d03b07e0ae9a3cf219 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/LofeltHaptics.framework.meta b/Assets/Plugins/iOS/LofeltHaptics.framework.meta new file mode 100644 index 0000000..91e3981 --- /dev/null +++ b/Assets/Plugins/iOS/LofeltHaptics.framework.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 3f3b3e40c5ec34183af765f15c1ce362 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/LofeltHaptics.framework/Headers/LofeltHaptics.h b/Assets/Plugins/iOS/LofeltHaptics.framework/Headers/LofeltHaptics.h new file mode 100644 index 0000000..848ed56 --- /dev/null +++ b/Assets/Plugins/iOS/LofeltHaptics.framework/Headers/LofeltHaptics.h @@ -0,0 +1,163 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +//! Project version number for LofeltHaptics. +FOUNDATION_EXPORT double LofeltHapticsVersionNumber; + +//! Project version string for LofeltHaptics. +FOUNDATION_EXPORT const unsigned char LofeltHapticsVersionString[]; + +//! Custom error domain +extern NSString *_Nonnull const LofeltErrorDomain; + +/*! + @class LofeltHaptics + @brief The LofeltHaptics class + @discussion Defines the API of Lofelt SDK for iOS. + + The LofeltHaptics class is not thread safe and can only be used from + the main thread. + + When the app is put into the background, Core Haptics will not allow + playing any haptics. LofeltHaptics will detect this situation and cease + all activity. + When the app is put into the foreground again, Core Haptics will allow + playing haptics again, and LofeltHaptics re-initalizes itself. However, + haptics that were interrupted when the app was backgrounded do not + automatically resume and need to be started again by calling @c play(). + @author Joao Freire, James Kneafsey, Thomas McGuire, Tomash GHz + @copyright © 2020 Lofelt. All rights reserved. + */ +@interface LofeltHaptics : NSObject +{ + void *_controller; + id _foregroundNotificationObserver; + id _backgroundNotificationObserver; +} + +/*! @abstract Checks if the iPhone meets the minimum requirements + @discussion This allows for a runtime check on iPhones that won't + meet the requirements for Lofelt Haptics. + + @return Whether the iPhone supports or not Lofelt Haptics + */ ++ (BOOL)deviceMeetsMinimumRequirement; + +- (instancetype)init NS_UNAVAILABLE; + +/*! @abstract Creates an instance of LofeltHaptics. + @discussion There should only be one instance of `LofeltHaptics` created in a given application. + @param error If the initialization fails, this will be set to a valid NSError describing the error. +*/ +- (nullable instancetype)initAndReturnError:(NSError **)error API_AVAILABLE(ios(13)) NS_SWIFT_NAME(init()); + +/*! @abstract Loads a haptic clip from string data. + @discussion The data must be in a valid Lofelt JSON format. + If a haptic clip is currently playing, it will be stopped. + @param data The Lofelt JSON format string. + @param error If the load operation fails, this will be set to a valid NSError describing the error. + @return Whether the operation succeeded +*/ +- (BOOL)load:(NSString *_Nonnull)data error:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract A version of @c load() taking @c NSData instead of @c NSString. + @discussion This method can be faster than @c load(), as it avoids string conversions. + @param data The .haptic clip, as UTF-8 encoded JSON string without a null terminator. + @param error If the load operation fails, this will be set to a valid NSError describing the error. + @return Whether the operation succeeded +*/ +- (BOOL)loadFromData:(NSData *_Nonnull)data error:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract Plays a loaded haptic clip. + @discussion The data must be preloaded using @c load() . + Only one haptic clip can play at a time. + Playback will start from the beginning of the haptic clip, or from the seek + position if seek() has been called before. + Calling play() if the clip is already playing has no effect. + @param error If the play operation fails, this will be set to a valid NSError describing the error. + @return Whether the operation succeeded +*/ +- (BOOL)play:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract Stops the haptic clip that is currently playing. + @discussion The call is ignored if no clip is loaded or no clip is playing. + @param error If the stop operation fails, this will be set to a valid NSError describing the error. + @return Whether the operation succeeded + */ +- (BOOL)stop:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract Jumps to a time position in the haptic clip + @discussion The playback state (playing or stopped) will not be changed unless seeking + beyond the end of the haptic clip. Seeking beyond the end of the clip will stop + playback. + Seeking to a negative position will start playback after a delay. + @param time The new position within the clip, as seconds from the beginning of the clip + @param error If the seek operation fails, this will be set to a valid NSError describing the error. + @return Whether the operation succeeded + */ +- (BOOL)seek:(float)time error:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract Multiplies the amplitude of every breakpoint of the clip with the given + multiplication factor + @discussion In other words, this function applies a gain (for factors greater than 1.0) + or an attenuation (for factors less than 1.0) to the clip. + If the resulting amplitude of a breakpoint is greater than 1.0, it is + clipped to 1.0. The amplitude is clipped hard, no limiter is used. + The clip needs to be loaded with @c load() first. Loading a clip resets + the multiplication factor back to the default of 1.0. + If no clip is currently playing, the multiplication will take effect + once @c play() is called. If a clip is currently playing, the multiplication + will take effect immediately. + @param amplitudeMultiplication The factor by which each amplitude will be multiplied. This value is a + multiplication factor, it is not a dB value. The factor needs to be 0 + or greater. + @param error If the operation fails, this will be set to a valid NSError describing + the error. An error can for example happen if no clip is loaded, or if + the factor is outside of the valid range. + @return Whether the operation succeeded + */ +- (BOOL)setAmplitudeMultiplication:(float)amplitudeMultiplication error:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract Adds the given shift to the frequency of every breakpoint in the clip, + including the emphasis. + @discussion In other words, this function shifts all frequencies of the clip. + If the resulting frequency of a breakpoint is smaller than 0.0 or + greater than 1.0, it is clipped to that range. The frequency is + clipped hard, no limiter is used. + The clip needs to be loaded with @c load() first. Loading a clip resets + the shift back to the default of 0.0. + If no clip is currently playing, the shift will take effect once @c play() + is called. If a clip is currently playing, the shift will take effect + immediately. + @param shift The amount by which each frequency should be shifted. This number is added + to each frequency value. The shift needs to be between -1.0 and 1.0. + @param error If the operation fails, this will be set to a valid NSError describing + the error. An error can for example happen if no clip is loaded, or if + the shift is outside of the valid range. + @return Whether the operation succeeded + */ +- (BOOL)setFrequencyShift:(float)shift error:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract Sets the playback to repeat from the start at the end of the clip. + @discussion Changes done with this function are only applied when @c play() is called. + When @c load() is called, looping is always disabled. + Playback will always start at the beginning of the clip, even if + @c seek() was used to jump to a different clip position before. + @param enabled When true, looping is set enabled; false disables looping. + @param error If the loop operation fails, this will be set to a valid NSError describing the error. + @return Whether the operation succeeded + */ +- (BOOL)loop:(BOOL)enabled error:(NSError *_Nullable *_Nullable)error API_AVAILABLE(ios(13)); + +/*! @abstract Returns the duration of the loaded clip + @discussion It will return 0.0 for an invalid clip + @return Duration of the loaded clip + */ +- (float)getClipDuration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Assets/Plugins/iOS/LofeltHaptics.framework/Info.plist b/Assets/Plugins/iOS/LofeltHaptics.framework/Info.plist new file mode 100644 index 0000000..370ca3a Binary files /dev/null and b/Assets/Plugins/iOS/LofeltHaptics.framework/Info.plist differ diff --git a/Assets/Plugins/iOS/LofeltHaptics.framework/LofeltHaptics b/Assets/Plugins/iOS/LofeltHaptics.framework/LofeltHaptics new file mode 100755 index 0000000..490f9f2 Binary files /dev/null and b/Assets/Plugins/iOS/LofeltHaptics.framework/LofeltHaptics differ diff --git a/Assets/Plugins/iOS/LofeltHaptics.framework/Modules/module.modulemap b/Assets/Plugins/iOS/LofeltHaptics.framework/Modules/module.modulemap new file mode 100644 index 0000000..44a6c28 --- /dev/null +++ b/Assets/Plugins/iOS/LofeltHaptics.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module LofeltHaptics { + umbrella header "LofeltHaptics.h" + + export * + module * { export * } +} diff --git a/Assets/Plugins/macOS.meta b/Assets/Plugins/macOS.meta new file mode 100644 index 0000000..34c7995 --- /dev/null +++ b/Assets/Plugins/macOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7aed595fe8f44c70b4bf38214153c03 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/macOS/libnice_vibrations_editor_plugin.dylib b/Assets/Plugins/macOS/libnice_vibrations_editor_plugin.dylib new file mode 100644 index 0000000..f237cdd Binary files /dev/null and b/Assets/Plugins/macOS/libnice_vibrations_editor_plugin.dylib differ diff --git a/Assets/Plugins/macOS/libnice_vibrations_editor_plugin.dylib.meta b/Assets/Plugins/macOS/libnice_vibrations_editor_plugin.dylib.meta new file mode 100644 index 0000000..c6ca628 --- /dev/null +++ b/Assets/Plugins/macOS/libnice_vibrations_editor_plugin.dylib.meta @@ -0,0 +1,80 @@ +fileFormatVersion: 2 +guid: 279c3792841e74f96b13b007d349facc +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 1 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: OSX + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/AudioData/AudioObject.bytes b/Assets/Resources/AudioData/AudioObject.bytes index 25220d6..fd3a83e 100644 Binary files a/Assets/Resources/AudioData/AudioObject.bytes and b/Assets/Resources/AudioData/AudioObject.bytes differ diff --git a/Assets/Resources/Audios/AnimCollision.wav.meta b/Assets/Resources/Audios/AnimCollision.wav.meta index 7d2597f..5f65318 100644 --- a/Assets/Resources/Audios/AnimCollision.wav.meta +++ b/Assets/Resources/Audios/AnimCollision.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/AnimToWeapon.wav.meta b/Assets/Resources/Audios/AnimToWeapon.wav.meta index 2858868..9e37989 100644 --- a/Assets/Resources/Audios/AnimToWeapon.wav.meta +++ b/Assets/Resources/Audios/AnimToWeapon.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/ArrowFire.wav.meta b/Assets/Resources/Audios/ArrowFire.wav.meta index cdf5237..1f1b073 100644 --- a/Assets/Resources/Audios/ArrowFire.wav.meta +++ b/Assets/Resources/Audios/ArrowFire.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/BoxBeSelected.wav.meta b/Assets/Resources/Audios/BoxBeSelected.wav.meta index c03457e..7c3f654 100644 --- a/Assets/Resources/Audios/BoxBeSelected.wav.meta +++ b/Assets/Resources/Audios/BoxBeSelected.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/BoxCollision.wav.meta b/Assets/Resources/Audios/BoxCollision.wav.meta index afae2ab..7138d7e 100644 --- a/Assets/Resources/Audios/BoxCollision.wav.meta +++ b/Assets/Resources/Audios/BoxCollision.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/BoxMove.wav.meta b/Assets/Resources/Audios/BoxMove.wav.meta index 8e0702e..2ff43d4 100644 --- a/Assets/Resources/Audios/BoxMove.wav.meta +++ b/Assets/Resources/Audios/BoxMove.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 01.wav.meta b/Assets/Resources/Audios/Chinese Number 01.wav.meta index 9e343e1..0a7a68a 100644 --- a/Assets/Resources/Audios/Chinese Number 01.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 01.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 02.wav.meta b/Assets/Resources/Audios/Chinese Number 02.wav.meta index e73fc44..d0f35be 100644 --- a/Assets/Resources/Audios/Chinese Number 02.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 02.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 03.wav.meta b/Assets/Resources/Audios/Chinese Number 03.wav.meta index 3df7517..42ea00b 100644 --- a/Assets/Resources/Audios/Chinese Number 03.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 03.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 04.wav.meta b/Assets/Resources/Audios/Chinese Number 04.wav.meta index d848af9..8f649b4 100644 --- a/Assets/Resources/Audios/Chinese Number 04.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 04.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 05.wav.meta b/Assets/Resources/Audios/Chinese Number 05.wav.meta index f74a935..c8ecd40 100644 --- a/Assets/Resources/Audios/Chinese Number 05.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 05.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 06.wav.meta b/Assets/Resources/Audios/Chinese Number 06.wav.meta index 2db7eff..1494a9a 100644 --- a/Assets/Resources/Audios/Chinese Number 06.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 06.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 07.wav.meta b/Assets/Resources/Audios/Chinese Number 07.wav.meta index e9a09c5..cbe107a 100644 --- a/Assets/Resources/Audios/Chinese Number 07.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 07.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 08.wav.meta b/Assets/Resources/Audios/Chinese Number 08.wav.meta index a0ffd9c..cfadd4b 100644 --- a/Assets/Resources/Audios/Chinese Number 08.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 08.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 09.wav.meta b/Assets/Resources/Audios/Chinese Number 09.wav.meta index 641b174..643eec3 100644 --- a/Assets/Resources/Audios/Chinese Number 09.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 09.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Chinese Number 10.wav.meta b/Assets/Resources/Audios/Chinese Number 10.wav.meta index c0a7b7b..00d487e 100644 --- a/Assets/Resources/Audios/Chinese Number 10.wav.meta +++ b/Assets/Resources/Audios/Chinese Number 10.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/CoinFly.wav.meta b/Assets/Resources/Audios/CoinFly.wav.meta index 8257983..fd45dc2 100644 --- a/Assets/Resources/Audios/CoinFly.wav.meta +++ b/Assets/Resources/Audios/CoinFly.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DamageByArrow.wav.meta b/Assets/Resources/Audios/DamageByArrow.wav.meta index daefd7a..70b36c3 100644 --- a/Assets/Resources/Audios/DamageByArrow.wav.meta +++ b/Assets/Resources/Audios/DamageByArrow.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DamageByBullet.wav.meta b/Assets/Resources/Audios/DamageByBullet.wav.meta index b39e166..8ec4b58 100644 --- a/Assets/Resources/Audios/DamageByBullet.wav.meta +++ b/Assets/Resources/Audios/DamageByBullet.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DamageByCannonBall.wav.meta b/Assets/Resources/Audios/DamageByCannonBall.wav.meta index 945cc09..03a359b 100644 --- a/Assets/Resources/Audios/DamageByCannonBall.wav.meta +++ b/Assets/Resources/Audios/DamageByCannonBall.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Defeat.wav.meta b/Assets/Resources/Audios/Defeat.wav.meta index 8c90e45..370413f 100644 --- a/Assets/Resources/Audios/Defeat.wav.meta +++ b/Assets/Resources/Audios/Defeat.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DestroyBox.wav.meta b/Assets/Resources/Audios/DestroyBox.wav.meta index 647087e..add1852 100644 --- a/Assets/Resources/Audios/DestroyBox.wav.meta +++ b/Assets/Resources/Audios/DestroyBox.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DevilAttackShield.wav.meta b/Assets/Resources/Audios/DevilAttackShield.wav.meta index 4a4c23b..3c3da55 100644 --- a/Assets/Resources/Audios/DevilAttackShield.wav.meta +++ b/Assets/Resources/Audios/DevilAttackShield.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DevilBeHit.wav.meta b/Assets/Resources/Audios/DevilBeHit.wav.meta index 97bf898..c9a1ad7 100644 --- a/Assets/Resources/Audios/DevilBeHit.wav.meta +++ b/Assets/Resources/Audios/DevilBeHit.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/DevilBeHit_01.wav.meta b/Assets/Resources/Audios/DevilBeHit_01.wav.meta index 7f52dca..7d53a68 100644 --- a/Assets/Resources/Audios/DevilBeHit_01.wav.meta +++ b/Assets/Resources/Audios/DevilBeHit_01.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DevilBeHit_02.wav.meta b/Assets/Resources/Audios/DevilBeHit_02.wav.meta index 6e5b479..2564d10 100644 --- a/Assets/Resources/Audios/DevilBeHit_02.wav.meta +++ b/Assets/Resources/Audios/DevilBeHit_02.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DevilBeHit_03.wav.meta b/Assets/Resources/Audios/DevilBeHit_03.wav.meta index f51f8ca..7ae3401 100644 --- a/Assets/Resources/Audios/DevilBeHit_03.wav.meta +++ b/Assets/Resources/Audios/DevilBeHit_03.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DevilDie.wav.meta b/Assets/Resources/Audios/DevilDie.wav.meta index 0218375..8299445 100644 --- a/Assets/Resources/Audios/DevilDie.wav.meta +++ b/Assets/Resources/Audios/DevilDie.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DevilFire.wav.meta b/Assets/Resources/Audios/DevilFire.wav.meta index a7e1753..0b969eb 100644 --- a/Assets/Resources/Audios/DevilFire.wav.meta +++ b/Assets/Resources/Audios/DevilFire.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DevilResurrection.wav.meta b/Assets/Resources/Audios/DevilResurrection.wav.meta index 365bf68..1e50185 100644 --- a/Assets/Resources/Audios/DevilResurrection.wav.meta +++ b/Assets/Resources/Audios/DevilResurrection.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DragonAttackShield.wav.meta b/Assets/Resources/Audios/DragonAttackShield.wav.meta index 12464a7..46750d6 100644 --- a/Assets/Resources/Audios/DragonAttackShield.wav.meta +++ b/Assets/Resources/Audios/DragonAttackShield.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DragonBeHit.wav.meta b/Assets/Resources/Audios/DragonBeHit.wav.meta index fe88035..5bb9944 100644 --- a/Assets/Resources/Audios/DragonBeHit.wav.meta +++ b/Assets/Resources/Audios/DragonBeHit.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DragonDie.wav.meta b/Assets/Resources/Audios/DragonDie.wav.meta index 56af9ce..33f1101 100644 --- a/Assets/Resources/Audios/DragonDie.wav.meta +++ b/Assets/Resources/Audios/DragonDie.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DragonFire.wav.meta b/Assets/Resources/Audios/DragonFire.wav.meta index 0157c2e..ca86a57 100644 --- a/Assets/Resources/Audios/DragonFire.wav.meta +++ b/Assets/Resources/Audios/DragonFire.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/DragonResurrection.wav.meta b/Assets/Resources/Audios/DragonResurrection.wav.meta index ccc779f..addb57b 100644 --- a/Assets/Resources/Audios/DragonResurrection.wav.meta +++ b/Assets/Resources/Audios/DragonResurrection.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/English Number 01.wav.meta b/Assets/Resources/Audios/English Number 01.wav.meta index 9f7d58a..33e0efc 100644 --- a/Assets/Resources/Audios/English Number 01.wav.meta +++ b/Assets/Resources/Audios/English Number 01.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 02.wav.meta b/Assets/Resources/Audios/English Number 02.wav.meta index 1004226..45b3ac6 100644 --- a/Assets/Resources/Audios/English Number 02.wav.meta +++ b/Assets/Resources/Audios/English Number 02.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 03.wav.meta b/Assets/Resources/Audios/English Number 03.wav.meta index 4325277..63abba0 100644 --- a/Assets/Resources/Audios/English Number 03.wav.meta +++ b/Assets/Resources/Audios/English Number 03.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 04.wav.meta b/Assets/Resources/Audios/English Number 04.wav.meta index 3dfba7a..8f35997 100644 --- a/Assets/Resources/Audios/English Number 04.wav.meta +++ b/Assets/Resources/Audios/English Number 04.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 05.wav.meta b/Assets/Resources/Audios/English Number 05.wav.meta index c76a38d..1f99f69 100644 --- a/Assets/Resources/Audios/English Number 05.wav.meta +++ b/Assets/Resources/Audios/English Number 05.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 06.wav.meta b/Assets/Resources/Audios/English Number 06.wav.meta index 43e1adc..5871670 100644 --- a/Assets/Resources/Audios/English Number 06.wav.meta +++ b/Assets/Resources/Audios/English Number 06.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 07.wav.meta b/Assets/Resources/Audios/English Number 07.wav.meta index cf35563..89711d3 100644 --- a/Assets/Resources/Audios/English Number 07.wav.meta +++ b/Assets/Resources/Audios/English Number 07.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 08.wav.meta b/Assets/Resources/Audios/English Number 08.wav.meta index c380619..4402dee 100644 --- a/Assets/Resources/Audios/English Number 08.wav.meta +++ b/Assets/Resources/Audios/English Number 08.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 09.wav.meta b/Assets/Resources/Audios/English Number 09.wav.meta index b723278..82007fa 100644 --- a/Assets/Resources/Audios/English Number 09.wav.meta +++ b/Assets/Resources/Audios/English Number 09.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/English Number 10.wav.meta b/Assets/Resources/Audios/English Number 10.wav.meta index 88fe658..d98ede6 100644 --- a/Assets/Resources/Audios/English Number 10.wav.meta +++ b/Assets/Resources/Audios/English Number 10.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/GhostAttackShield.wav.meta b/Assets/Resources/Audios/GhostAttackShield.wav.meta index 856d3c9..5807e68 100644 --- a/Assets/Resources/Audios/GhostAttackShield.wav.meta +++ b/Assets/Resources/Audios/GhostAttackShield.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/GhostBeHit.wav.meta b/Assets/Resources/Audios/GhostBeHit.wav.meta index 8456412..11b9596 100644 --- a/Assets/Resources/Audios/GhostBeHit.wav.meta +++ b/Assets/Resources/Audios/GhostBeHit.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/GhostDie.wav.meta b/Assets/Resources/Audios/GhostDie.wav.meta index 634181c..dbd407c 100644 --- a/Assets/Resources/Audios/GhostDie.wav.meta +++ b/Assets/Resources/Audios/GhostDie.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/GhostFire.wav.meta b/Assets/Resources/Audios/GhostFire.wav.meta index 6c43515..64d712d 100644 --- a/Assets/Resources/Audios/GhostFire.wav.meta +++ b/Assets/Resources/Audios/GhostFire.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/GhostResurrection.wav.meta b/Assets/Resources/Audios/GhostResurrection.wav.meta index 249d67a..cdb457c 100644 --- a/Assets/Resources/Audios/GhostResurrection.wav.meta +++ b/Assets/Resources/Audios/GhostResurrection.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/GunFire.wav.meta b/Assets/Resources/Audios/GunFire.wav.meta index d876cb4..c0931be 100644 --- a/Assets/Resources/Audios/GunFire.wav.meta +++ b/Assets/Resources/Audios/GunFire.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/HorseMove.wav.meta b/Assets/Resources/Audios/HorseMove.wav.meta index d7a0947..65f226d 100644 --- a/Assets/Resources/Audios/HorseMove.wav.meta +++ b/Assets/Resources/Audios/HorseMove.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Japanese Number 01.wav.meta b/Assets/Resources/Audios/Japanese Number 01.wav.meta index 60808a4..08a871e 100644 --- a/Assets/Resources/Audios/Japanese Number 01.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 01.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 02.wav.meta b/Assets/Resources/Audios/Japanese Number 02.wav.meta index 70d4c03..6564a8f 100644 --- a/Assets/Resources/Audios/Japanese Number 02.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 02.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 03.wav.meta b/Assets/Resources/Audios/Japanese Number 03.wav.meta index 6de1165..c19bafc 100644 --- a/Assets/Resources/Audios/Japanese Number 03.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 03.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 04.wav.meta b/Assets/Resources/Audios/Japanese Number 04.wav.meta index 49af731..dd58a30 100644 --- a/Assets/Resources/Audios/Japanese Number 04.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 04.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 05.wav.meta b/Assets/Resources/Audios/Japanese Number 05.wav.meta index b926c4d..1d99983 100644 --- a/Assets/Resources/Audios/Japanese Number 05.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 05.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 06.wav.meta b/Assets/Resources/Audios/Japanese Number 06.wav.meta index b32ff04..74803fd 100644 --- a/Assets/Resources/Audios/Japanese Number 06.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 06.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 07.wav.meta b/Assets/Resources/Audios/Japanese Number 07.wav.meta index 0f49b11..2ce1b7a 100644 --- a/Assets/Resources/Audios/Japanese Number 07.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 07.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 08.wav.meta b/Assets/Resources/Audios/Japanese Number 08.wav.meta index b40b9f0..ef709bc 100644 --- a/Assets/Resources/Audios/Japanese Number 08.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 08.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 09.wav.meta b/Assets/Resources/Audios/Japanese Number 09.wav.meta index cbf9245..6363152 100644 --- a/Assets/Resources/Audios/Japanese Number 09.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 09.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Japanese Number 10.wav.meta b/Assets/Resources/Audios/Japanese Number 10.wav.meta index 1a3d21a..80884d6 100644 --- a/Assets/Resources/Audios/Japanese Number 10.wav.meta +++ b/Assets/Resources/Audios/Japanese Number 10.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/LevelBegins.wav.meta b/Assets/Resources/Audios/LevelBegins.wav.meta index 48b22d1..55b0f30 100644 --- a/Assets/Resources/Audios/LevelBegins.wav.meta +++ b/Assets/Resources/Audios/LevelBegins.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/NVDice.wav b/Assets/Resources/Audios/NVDice.wav new file mode 100644 index 0000000..fca849c Binary files /dev/null and b/Assets/Resources/Audios/NVDice.wav differ diff --git a/Assets/Resources/Audios/NVDice.wav.meta b/Assets/Resources/Audios/NVDice.wav.meta new file mode 100644 index 0000000..e1125fc --- /dev/null +++ b/Assets/Resources/Audios/NVDice.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 95f3e694b4c5b4892871f69fd96b4b7f +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/NVHeartbeats.wav b/Assets/Resources/Audios/NVHeartbeats.wav new file mode 100644 index 0000000..faf3c74 Binary files /dev/null and b/Assets/Resources/Audios/NVHeartbeats.wav differ diff --git a/Assets/Resources/Audios/NVHeartbeats.wav.meta b/Assets/Resources/Audios/NVHeartbeats.wav.meta new file mode 100644 index 0000000..ee959b9 --- /dev/null +++ b/Assets/Resources/Audios/NVHeartbeats.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: b02578356d1b84c5fb7f4d3efb784def +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/PrincessDown.wav.meta b/Assets/Resources/Audios/PrincessDown.wav.meta index 7dd9847..f2d2975 100644 --- a/Assets/Resources/Audios/PrincessDown.wav.meta +++ b/Assets/Resources/Audios/PrincessDown.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/PrincessFear.wav.meta b/Assets/Resources/Audios/PrincessFear.wav.meta index b6e53b6..0127709 100644 --- a/Assets/Resources/Audios/PrincessFear.wav.meta +++ b/Assets/Resources/Audios/PrincessFear.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/ShieldBroken.wav.meta b/Assets/Resources/Audios/ShieldBroken.wav.meta index e52ca53..6702d32 100644 --- a/Assets/Resources/Audios/ShieldBroken.wav.meta +++ b/Assets/Resources/Audios/ShieldBroken.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/ShieldUnderAttack.wav.meta b/Assets/Resources/Audios/ShieldUnderAttack.wav.meta index 8045fe4..c3ad167 100644 --- a/Assets/Resources/Audios/ShieldUnderAttack.wav.meta +++ b/Assets/Resources/Audios/ShieldUnderAttack.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Spanish Number 01.wav.meta b/Assets/Resources/Audios/Spanish Number 01.wav.meta index eb5f9f8..acee4a2 100644 --- a/Assets/Resources/Audios/Spanish Number 01.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 01.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 02.wav.meta b/Assets/Resources/Audios/Spanish Number 02.wav.meta index 805d9b1..08547ac 100644 --- a/Assets/Resources/Audios/Spanish Number 02.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 02.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 03.wav.meta b/Assets/Resources/Audios/Spanish Number 03.wav.meta index 007ca79..5cb0a34 100644 --- a/Assets/Resources/Audios/Spanish Number 03.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 03.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 04.wav.meta b/Assets/Resources/Audios/Spanish Number 04.wav.meta index d535408..d44abc9 100644 --- a/Assets/Resources/Audios/Spanish Number 04.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 04.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 05.wav.meta b/Assets/Resources/Audios/Spanish Number 05.wav.meta index 51cd4ec..3af7265 100644 --- a/Assets/Resources/Audios/Spanish Number 05.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 05.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 06.wav.meta b/Assets/Resources/Audios/Spanish Number 06.wav.meta index 1b7d732..5372407 100644 --- a/Assets/Resources/Audios/Spanish Number 06.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 06.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 07.wav.meta b/Assets/Resources/Audios/Spanish Number 07.wav.meta index dab46c9..8fee19a 100644 --- a/Assets/Resources/Audios/Spanish Number 07.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 07.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 08.wav.meta b/Assets/Resources/Audios/Spanish Number 08.wav.meta index 207643b..f2e4874 100644 --- a/Assets/Resources/Audios/Spanish Number 08.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 08.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 09.wav.meta b/Assets/Resources/Audios/Spanish Number 09.wav.meta index eca3692..9f2b06c 100644 --- a/Assets/Resources/Audios/Spanish Number 09.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 09.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spanish Number 10.wav.meta b/Assets/Resources/Audios/Spanish Number 10.wav.meta index 128f81d..4fe6cdb 100644 --- a/Assets/Resources/Audios/Spanish Number 10.wav.meta +++ b/Assets/Resources/Audios/Spanish Number 10.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/Spin.wav.meta b/Assets/Resources/Audios/Spin.wav.meta index 62661e7..428d036 100644 --- a/Assets/Resources/Audios/Spin.wav.meta +++ b/Assets/Resources/Audios/Spin.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/TigerMove.wav.meta b/Assets/Resources/Audios/TigerMove.wav.meta index 410df8e..e322052 100644 --- a/Assets/Resources/Audios/TigerMove.wav.meta +++ b/Assets/Resources/Audios/TigerMove.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/UnlockProp.wav.meta b/Assets/Resources/Audios/UnlockProp.wav.meta index f929c98..8ffb0e1 100644 --- a/Assets/Resources/Audios/UnlockProp.wav.meta +++ b/Assets/Resources/Audios/UnlockProp.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/UnlockTurret.wav.meta b/Assets/Resources/Audios/UnlockTurret.wav.meta index 5c6df92..5e97a9f 100644 --- a/Assets/Resources/Audios/UnlockTurret.wav.meta +++ b/Assets/Resources/Audios/UnlockTurret.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/Victory.wav.meta b/Assets/Resources/Audios/Victory.wav.meta index bd4a9b4..2ef0cec 100644 --- a/Assets/Resources/Audios/Victory.wav.meta +++ b/Assets/Resources/Audios/Victory.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/WeaponExhausted.wav.meta b/Assets/Resources/Audios/WeaponExhausted.wav.meta index 0421b69..cc4593b 100644 --- a/Assets/Resources/Audios/WeaponExhausted.wav.meta +++ b/Assets/Resources/Audios/WeaponExhausted.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/WeaponFire.wav.meta b/Assets/Resources/Audios/WeaponFire.wav.meta index 2325452..1a18c1d 100644 --- a/Assets/Resources/Audios/WeaponFire.wav.meta +++ b/Assets/Resources/Audios/WeaponFire.wav.meta @@ -6,10 +6,10 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 0.29999998 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/au_bgm_coreplay.wav.meta b/Assets/Resources/Audios/au_bgm_coreplay.wav.meta index f1c74fc..238c2f8 100644 --- a/Assets/Resources/Audios/au_bgm_coreplay.wav.meta +++ b/Assets/Resources/Audios/au_bgm_coreplay.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/au_bgm_home.wav.meta b/Assets/Resources/Audios/au_bgm_home.wav.meta index b68371d..b32696a 100644 --- a/Assets/Resources/Audios/au_bgm_home.wav.meta +++ b/Assets/Resources/Audios/au_bgm_home.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/au_coreplay_choose_v120_a.wav b/Assets/Resources/Audios/au_coreplay_choose_v120_a.wav new file mode 100644 index 0000000..11bda3d Binary files /dev/null and b/Assets/Resources/Audios/au_coreplay_choose_v120_a.wav differ diff --git a/Assets/Resources/Audios/au_coreplay_choose_v120_a.wav.meta b/Assets/Resources/Audios/au_coreplay_choose_v120_a.wav.meta new file mode 100644 index 0000000..2ef1475 --- /dev/null +++ b/Assets/Resources/Audios/au_coreplay_choose_v120_a.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: a4397a33fe4d245cc99d63997647d8cd +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_coreplay_clear_v120_a.wav b/Assets/Resources/Audios/au_coreplay_clear_v120_a.wav new file mode 100755 index 0000000..ab3a0d1 Binary files /dev/null and b/Assets/Resources/Audios/au_coreplay_clear_v120_a.wav differ diff --git a/Assets/Resources/Audios/au_coreplay_clear_v120_a.wav.meta b/Assets/Resources/Audios/au_coreplay_clear_v120_a.wav.meta new file mode 100644 index 0000000..e6567e0 --- /dev/null +++ b/Assets/Resources/Audios/au_coreplay_clear_v120_a.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 64e1436220f4d401995ec856766c2e7a +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_coreplay_unchoose_v120_a.wav b/Assets/Resources/Audios/au_coreplay_unchoose_v120_a.wav new file mode 100644 index 0000000..63edb1f Binary files /dev/null and b/Assets/Resources/Audios/au_coreplay_unchoose_v120_a.wav differ diff --git a/Assets/Resources/Audios/au_coreplay_unchoose_v120_a.wav.meta b/Assets/Resources/Audios/au_coreplay_unchoose_v120_a.wav.meta new file mode 100644 index 0000000..8b78cc9 --- /dev/null +++ b/Assets/Resources/Audios/au_coreplay_unchoose_v120_a.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 6aa709a35a9da42029251eb3819256cf +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_notice_level_countDown_edge.wav b/Assets/Resources/Audios/au_sfx_notice_level_countDown_edge.wav new file mode 100644 index 0000000..51bfc93 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_notice_level_countDown_edge.wav differ diff --git a/Assets/Resources/Audios/au_sfx_notice_level_countDown_edge.wav.meta b/Assets/Resources/Audios/au_sfx_notice_level_countDown_edge.wav.meta new file mode 100644 index 0000000..1bbfce8 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_notice_level_countDown_edge.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: e640dc3c900064126804112a521170ea +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_notice_level_countDown_time.wav b/Assets/Resources/Audios/au_sfx_notice_level_countDown_time.wav new file mode 100644 index 0000000..42a21ac Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_notice_level_countDown_time.wav differ diff --git a/Assets/Resources/Audios/au_sfx_notice_level_countDown_time.wav.meta b/Assets/Resources/Audios/au_sfx_notice_level_countDown_time.wav.meta new file mode 100644 index 0000000..200ccc8 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_notice_level_countDown_time.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: be8f215dba3904ddf9f72fc064c97e71 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud1.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud1.wav new file mode 100644 index 0000000..d2e2e8c Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud1.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud1.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud1.wav.meta new file mode 100644 index 0000000..1c31459 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud1.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: e01161c5ac9a44c29826c87aef56bc85 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud2.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud2.wav new file mode 100644 index 0000000..dd4fc16 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud2.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud2.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud2.wav.meta new file mode 100644 index 0000000..fc483d4 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud2.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 61608f7e047d4485bbc30b5ddd8cec5e +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud3.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud3.wav new file mode 100644 index 0000000..935c41d Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud3.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud3.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud3.wav.meta new file mode 100644 index 0000000..1c87d13 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_cloud3.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: cbe1f9ae435844fc68535585de6a7968 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice1.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice1.wav new file mode 100644 index 0000000..54b5a02 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice1.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice1.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice1.wav.meta new file mode 100644 index 0000000..0e96772 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice1.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 5c8f89c6913b4476fa87963914fbd8ad +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice2.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice2.wav new file mode 100644 index 0000000..725d7a7 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice2.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice2.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice2.wav.meta new file mode 100644 index 0000000..ff44951 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice2.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 0c17690bc257842a596a6506d05faaac +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice3.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice3.wav new file mode 100644 index 0000000..0660064 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice3.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice3.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice3.wav.meta new file mode 100644 index 0000000..a141a3e --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_choose_ice3.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 115a82924c82b432b9b9d1639dd840ea +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud1.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud1.wav new file mode 100644 index 0000000..706a54c Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud1.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud1.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud1.wav.meta new file mode 100644 index 0000000..826f10e --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud1.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 50382ffb9ae0941d191a1fab99d72ed8 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud2.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud2.wav new file mode 100644 index 0000000..b888309 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud2.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud2.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud2.wav.meta new file mode 100644 index 0000000..e5d96c6 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud2.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 6db1f59903e64438a9ec6c5bfb6b356a +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud3.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud3.wav new file mode 100644 index 0000000..d766761 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud3.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud3.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud3.wav.meta new file mode 100644 index 0000000..51c3af1 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_cloud3.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: f30159797c65949c4b62554227e06ab7 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice1.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice1.wav new file mode 100644 index 0000000..54ff000 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice1.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice1.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice1.wav.meta new file mode 100644 index 0000000..c606f2d --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice1.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 8c2fd558ca9764b088c75fd1ac9b33fc +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice2.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice2.wav new file mode 100644 index 0000000..dd672c9 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice2.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice2.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice2.wav.meta new file mode 100644 index 0000000..40ad787 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice2.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 787f7f6573521464c83b4db264b42338 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice3.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice3.wav new file mode 100644 index 0000000..d74b64f Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice3.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice3.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice3.wav.meta new file mode 100644 index 0000000..5439d6c --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_clear_ice3.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: c1da157e1c4ef48488cf20c909aca237 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud1.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud1.wav new file mode 100644 index 0000000..6be8e16 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud1.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud1.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud1.wav.meta new file mode 100644 index 0000000..5d87d3a --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud1.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 500927f6125c8460da8b59798919f8c5 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud2.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud2.wav new file mode 100644 index 0000000..efa7608 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud2.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud2.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud2.wav.meta new file mode 100644 index 0000000..7204d01 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud2.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: bcae844b708874c8d93054abbff8f578 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud3.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud3.wav new file mode 100644 index 0000000..782ee4f Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud3.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud3.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud3.wav.meta new file mode 100644 index 0000000..dbafa4f --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_cloud3.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 0f7651a5f9baa4e1a9ce848455f6a5e5 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice1.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice1.wav new file mode 100644 index 0000000..a805070 Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice1.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice1.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice1.wav.meta new file mode 100644 index 0000000..7c65bc6 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice1.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: bd51e45fa0b7745f4b2a3368868e7cf4 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice2.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice2.wav new file mode 100644 index 0000000..b50fd1e Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice2.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice2.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice2.wav.meta new file mode 100644 index 0000000..4554202 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice2.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 86e2506072cae4ddca84c3a1719a1860 +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice3.wav b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice3.wav new file mode 100644 index 0000000..f228b1c Binary files /dev/null and b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice3.wav differ diff --git a/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice3.wav.meta b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice3.wav.meta new file mode 100644 index 0000000..8495574 --- /dev/null +++ b/Assets/Resources/Audios/au_sfx_ui_button_corePlay_unchoose_ice3.wav.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 8616f153dfd974b99b6f48ac3a87d6fc +AudioImporter: + externalObjects: {} + serializedVersion: 7 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 2 + sampleRateOverride: 22050 + compressionFormat: 1 + quality: 0.5 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Audios/au_stream.ogg.meta b/Assets/Resources/Audios/au_stream.ogg.meta index 823ca83..e428de1 100644 --- a/Assets/Resources/Audios/au_stream.ogg.meta +++ b/Assets/Resources/Audios/au_stream.ogg.meta @@ -5,11 +5,11 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 - sampleRateOverride: 44100 + loadType: 2 + sampleRateSetting: 2 + sampleRateOverride: 22050 compressionFormat: 1 - quality: 1 + quality: 0.5 conversionMode: 0 preloadAudioData: 0 platformSettingOverrides: {} diff --git a/Assets/Resources/Audios/music_home_base_01_16.wav.meta b/Assets/Resources/Audios/music_home_base_01_16.wav.meta index 1afdc42..634b63d 100644 --- a/Assets/Resources/Audios/music_home_base_01_16.wav.meta +++ b/Assets/Resources/Audios/music_home_base_01_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_base_02.wav.meta b/Assets/Resources/Audios/music_home_base_02.wav.meta index 6a2aa73..5482691 100644 --- a/Assets/Resources/Audios/music_home_base_02.wav.meta +++ b/Assets/Resources/Audios/music_home_base_02.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_base_03.wav.meta b/Assets/Resources/Audios/music_home_base_03.wav.meta index 114c4e0..c0f5d95 100644 --- a/Assets/Resources/Audios/music_home_base_03.wav.meta +++ b/Assets/Resources/Audios/music_home_base_03.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_drum_01_p1b_16.wav.meta b/Assets/Resources/Audios/music_home_drum_01_p1b_16.wav.meta index fbc84e3..361c92e 100644 --- a/Assets/Resources/Audios/music_home_drum_01_p1b_16.wav.meta +++ b/Assets/Resources/Audios/music_home_drum_01_p1b_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_drum_02_p1b.wav.meta b/Assets/Resources/Audios/music_home_drum_02_p1b.wav.meta index 8258a47..9a941dd 100644 --- a/Assets/Resources/Audios/music_home_drum_02_p1b.wav.meta +++ b/Assets/Resources/Audios/music_home_drum_02_p1b.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_drum_03_16.wav.meta b/Assets/Resources/Audios/music_home_drum_03_16.wav.meta index d5f4ad6..f1ae74c 100644 --- a/Assets/Resources/Audios/music_home_drum_03_16.wav.meta +++ b/Assets/Resources/Audios/music_home_drum_03_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_epiano_01_16.wav.meta b/Assets/Resources/Audios/music_home_epiano_01_16.wav.meta index 19858c7..40e908a 100644 --- a/Assets/Resources/Audios/music_home_epiano_01_16.wav.meta +++ b/Assets/Resources/Audios/music_home_epiano_01_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_epiano_01_v2_16.wav.meta b/Assets/Resources/Audios/music_home_epiano_01_v2_16.wav.meta index 3c8cee7..f295d53 100644 --- a/Assets/Resources/Audios/music_home_epiano_01_v2_16.wav.meta +++ b/Assets/Resources/Audios/music_home_epiano_01_v2_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_epiano_02_16.wav.meta b/Assets/Resources/Audios/music_home_epiano_02_16.wav.meta index 4653e04..44b2548 100644 --- a/Assets/Resources/Audios/music_home_epiano_02_16.wav.meta +++ b/Assets/Resources/Audios/music_home_epiano_02_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_guitar_01_16.wav.meta b/Assets/Resources/Audios/music_home_guitar_01_16.wav.meta index fb66248..16e6577 100644 --- a/Assets/Resources/Audios/music_home_guitar_01_16.wav.meta +++ b/Assets/Resources/Audios/music_home_guitar_01_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_guitar_02_16.wav.meta b/Assets/Resources/Audios/music_home_guitar_02_16.wav.meta index a6583fc..2e3c064 100644 --- a/Assets/Resources/Audios/music_home_guitar_02_16.wav.meta +++ b/Assets/Resources/Audios/music_home_guitar_02_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_guitar_03_16.wav.meta b/Assets/Resources/Audios/music_home_guitar_03_16.wav.meta index 9a54b44..2f3a04f 100644 --- a/Assets/Resources/Audios/music_home_guitar_03_16.wav.meta +++ b/Assets/Resources/Audios/music_home_guitar_03_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_guitar_04_16.wav.meta b/Assets/Resources/Audios/music_home_guitar_04_16.wav.meta index effb45b..fcd574b 100644 --- a/Assets/Resources/Audios/music_home_guitar_04_16.wav.meta +++ b/Assets/Resources/Audios/music_home_guitar_04_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_guitar_05_16.wav.meta b/Assets/Resources/Audios/music_home_guitar_05_16.wav.meta index bf5fe79..0400f96 100644 --- a/Assets/Resources/Audios/music_home_guitar_05_16.wav.meta +++ b/Assets/Resources/Audios/music_home_guitar_05_16.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_other.wav.meta b/Assets/Resources/Audios/music_home_other.wav.meta index 42f773a..fcc0e36 100644 --- a/Assets/Resources/Audios/music_home_other.wav.meta +++ b/Assets/Resources/Audios/music_home_other.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 2 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_transition_downward.wav.meta b/Assets/Resources/Audios/music_home_transition_downward.wav.meta index 8a5645f..cffcb96 100644 --- a/Assets/Resources/Audios/music_home_transition_downward.wav.meta +++ b/Assets/Resources/Audios/music_home_transition_downward.wav.meta @@ -5,13 +5,13 @@ AudioImporter: serializedVersion: 7 defaultSettings: serializedVersion: 2 - loadType: 0 - sampleRateSetting: 0 + loadType: 1 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/Audios/music_home_transition_upward.wav.meta b/Assets/Resources/Audios/music_home_transition_upward.wav.meta index c70fa3e..8dc5944 100644 --- a/Assets/Resources/Audios/music_home_transition_upward.wav.meta +++ b/Assets/Resources/Audios/music_home_transition_upward.wav.meta @@ -6,12 +6,12 @@ AudioImporter: defaultSettings: serializedVersion: 2 loadType: 0 - sampleRateSetting: 0 + sampleRateSetting: 2 sampleRateOverride: 44100 compressionFormat: 1 - quality: 1 + quality: 0.13 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 diff --git a/Assets/Resources/HapticData.meta b/Assets/Resources/HapticData.meta new file mode 100644 index 0000000..0a225c5 --- /dev/null +++ b/Assets/Resources/HapticData.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a6d0c35bae9a4c8aa77f808ab4f0763 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/HapticData/HapticObject.bytes b/Assets/Resources/HapticData/HapticObject.bytes new file mode 100644 index 0000000..6c8776c Binary files /dev/null and b/Assets/Resources/HapticData/HapticObject.bytes differ diff --git a/Assets/Resources/HapticData/HapticObject.bytes.meta b/Assets/Resources/HapticData/HapticObject.bytes.meta new file mode 100644 index 0000000..b42c7c5 --- /dev/null +++ b/Assets/Resources/HapticData/HapticObject.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c8d35819e27b74a96b9b9358d9e9fd35 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Haptics.meta b/Assets/Resources/Haptics.meta new file mode 100644 index 0000000..8331401 --- /dev/null +++ b/Assets/Resources/Haptics.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9f3bf7ca3a7e43de8cf38e1a68b92bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Haptics/NVDice.haptic b/Assets/Resources/Haptics/NVDice.haptic new file mode 100644 index 0000000..b76f105 --- /dev/null +++ b/Assets/Resources/Haptics/NVDice.haptic @@ -0,0 +1 @@ +{"version":{"major":1,"minor":0,"patch":0},"metadata":{"author":"joao@lofelt.com","editor":"Lofelt Studio","source":"AHAPPresets/NVDice.wav","project":"NVDice","tags":[],"description":""},"signals":{"continuous":{"envelopes":{"amplitude":[{"time":0,"amplitude":0.00029056615},{"time":0.0010204081,"amplitude":0.00029056615},{"time":0.020022675,"amplitude":0.0010838391},{"time":0.023015874,"amplitude":0.24628326,"emphasis":{"amplitude":0.64811385,"frequency":1}},{"time":0.04301587,"amplitude":0.30893233},{"time":0.06201814,"amplitude":0.14449422},{"time":0.0870068,"amplitude":0.058487773},{"time":0.090022676,"amplitude":0.21247946,"emphasis":{"amplitude":0.5591565,"frequency":0.1768105}},{"time":0.114013605,"amplitude":0.21455966},{"time":0.14301588,"amplitude":0.06968115},{"time":0.21102041,"amplitude":0.031449247},{"time":0.21201813,"amplitude":0.24404025,"emphasis":{"amplitude":0.6422112,"frequency":0.2923607}},{"time":0.23301587,"amplitude":0.28606227},{"time":0.26600906,"amplitude":0.07495963},{"time":0.26700678,"amplitude":0.6502027},{"time":0.27002266,"amplitude":0.308164,"emphasis":{"amplitude":0.8109579,"frequency":0.618822}},{"time":0.28301588,"amplitude":0.49409807},{"time":0.30301586,"amplitude":0.21208319},{"time":0.3170068,"amplitude":0.120308496},{"time":0.35201815,"amplitude":0.044048432},{"time":0.35301587,"amplitude":0.597531},{"time":0.37201813,"amplitude":0.29360098},{"time":0.3840136,"amplitude":0.17828391},{"time":0.38501135,"amplitude":0.3910198},{"time":0.41201812,"amplitude":0.14365426},{"time":0.42501134,"amplitude":0.18421979},{"time":0.4640136,"amplitude":0.043719392},{"time":0.46501133,"amplitude":0.13552359},{"time":0.48,"amplitude":0.08007864},{"time":0.48600906,"amplitude":0.17900568},{"time":0.5050113,"amplitude":0.090373725},{"time":0.57900226,"amplitude":0.023051888},{"time":0.58,"amplitude":0.07891691},{"time":0.61,"amplitude":0.024494085},{"time":0.61099774,"amplitude":0.10730806},{"time":0.65,"amplitude":0.023467101},{"time":0.6509977,"amplitude":0.056163862},{"time":0.69600904,"amplitude":0.013153992},{"time":0.7140136,"amplitude":0.06063435},{"time":0.77900225,"amplitude":0.0046691853},{"time":0.9629932,"amplitude":0.0005919837},{"time":0.9633333,"amplitude":0.0005919837},{"time":0.9633333,"amplitude":0.0005919837}],"frequency":[{"time":0,"frequency":1},{"time":0.0058049876,"frequency":0.45383245},{"time":0.043537416,"frequency":0.74745363},{"time":0.13931973,"frequency":0.574811},{"time":0.18575963,"frequency":0.7171733},{"time":0.20897959,"frequency":0.5531693},{"time":0.23510204,"frequency":0.6953524},{"time":0.26702946,"frequency":0.52940357},{"time":0.30476192,"frequency":0.6585863},{"time":0.38893422,"frequency":0.5463057},{"time":0.41505668,"frequency":0.68535703},{"time":0.42376417,"frequency":0.54946226},{"time":0.4614966,"frequency":0.5811323},{"time":0.53696144,"frequency":0.54777396},{"time":0.6066213,"frequency":0.5811939},{"time":0.64435375,"frequency":0.72476804},{"time":0.6675737,"frequency":0.5684711},{"time":0.6849887,"frequency":0.9723859},{"time":0.69659865,"frequency":0.66252524},{"time":0.751746,"frequency":0.6206365},{"time":0.757551,"frequency":0.97920614},{"time":0.7662585,"frequency":0.6674669},{"time":0.786576,"frequency":0.679469},{"time":0.8039909,"frequency":0.99255854},{"time":0.8185034,"frequency":0.6613598},{"time":0.83591837,"frequency":1},{"time":0.85043085,"frequency":0.635323},{"time":0.8649433,"frequency":0.65902764},{"time":0.8707483,"frequency":1},{"time":0.94911563,"frequency":1}]}}}} \ No newline at end of file diff --git a/Assets/Resources/Haptics/NVDice.haptic.meta b/Assets/Resources/Haptics/NVDice.haptic.meta new file mode 100644 index 0000000..b0719a3 --- /dev/null +++ b/Assets/Resources/Haptics/NVDice.haptic.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c17ef63f85d68483fbc6f771d5618568 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: dc84fb4fa9e67485a972c887d976d004, type: 3} diff --git a/Assets/Resources/Haptics/NVHeartbeats.haptic b/Assets/Resources/Haptics/NVHeartbeats.haptic new file mode 100644 index 0000000..c061759 --- /dev/null +++ b/Assets/Resources/Haptics/NVHeartbeats.haptic @@ -0,0 +1 @@ +{"version":{"major":1,"minor":0,"patch":0},"metadata":{"author":"joao@lofelt.com","editor":"Lofelt Studio","source":"AHAPPresets/NVHeartbeats.wav","project":"NVHeartbeats","tags":[],"description":""},"signals":{"continuous":{"envelopes":{"amplitude":[{"time":0,"amplitude":0.009742844},{"time":0.0010204081,"amplitude":0.009742844},{"time":0.003015873,"amplitude":0.19868761},{"time":0.0070068026,"amplitude":0.21186994},{"time":0.009002267,"amplitude":0.3535316},{"time":0.018004535,"amplitude":0.32513767},{"time":0.029002268,"amplitude":0.2547701},{"time":0.045011338,"amplitude":0.18802175},{"time":0.06301587,"amplitude":0.13030155},{"time":0.083015874,"amplitude":0.085643366},{"time":0.10401361,"amplitude":0.055023465},{"time":0.12900226,"amplitude":0.031824943},{"time":0.18501133,"amplitude":0.008188676},{"time":0.22900227,"amplitude":0.0017238385},{"time":0.29999998,"amplitude":0.000433428},{"time":0.3010204,"amplitude":0.023433387},{"time":0.3040086,"amplitude":0.3662426,"emphasis":{"amplitude":0.8550492434482757,"frequency":1}},{"time":0.3040136,"amplitude":0.5318154},{"time":0.3070068,"amplitude":0.50587577},{"time":0.30900225,"amplitude":0.8576526},{"time":0.31201813,"amplitude":0.8540082},{"time":0.31501132,"amplitude":0.78581953},{"time":0.31900227,"amplitude":0.79041666},{"time":0.32900226,"amplitude":0.6319953},{"time":0.3370068,"amplitude":0.54113984},{"time":0.3540136,"amplitude":0.38007545},{"time":0.37301588,"amplitude":0.25503132},{"time":0.39301586,"amplitude":0.16664001},{"time":0.4170068,"amplitude":0.098586604},{"time":0.4540136,"amplitude":0.042635933},{"time":0.48301587,"amplitude":0.020449765},{"time":0.53301585,"amplitude":0.0033419875},{"time":0.5770068,"amplitude":0.0005798723},{"time":0.9,"amplitude":0.0004947566},{"time":0.9020066357822161,"amplitude":0.10341841455295508},{"time":0.9029932,"amplitude":0.15402092,"emphasis":{"amplitude":0.18556738,"frequency":0.14043266}},{"time":0.9050361486566805,"amplitude":0.17912326986405525},{"time":0.9070068,"amplitude":0.20333728},{"time":0.90900224,"amplitude":0.34423363},{"time":0.9370068,"amplitude":0.21514598},{"time":0.9550113,"amplitude":0.1495948},{"time":0.9729932,"amplitude":0.10280151},{"time":1.0009977,"amplitude":0.059750818},{"time":1.0019954,"amplitude":0.057907753},{"time":1.0170068,"amplitude":0.04022924},{"time":1.0429932,"amplitude":0.022579549},{"time":1.0670068,"amplitude":0.012942444},{"time":1.1,"amplitude":0.0051094904},{"time":1.1520181,"amplitude":0.0006914464},{"time":1.2000227,"amplitude":0.00037157716},{"time":1.2010204,"amplitude":0.016553689},{"time":1.2040085999999999,"amplitude":0.36852205,"emphasis":{"amplitude":0.8336576524137936,"frequency":0.96081686}},{"time":1.2040136,"amplitude":0.53432286},{"time":1.2070068,"amplitude":0.50807685},{"time":1.2090023,"amplitude":0.85174495},{"time":1.2100227,"amplitude":0.8910244},{"time":1.2120181,"amplitude":0.87354046},{"time":1.2140136,"amplitude":0.81445026},{"time":1.2180045,"amplitude":0.7936242},{"time":1.2210203,"amplitude":0.72203946},{"time":1.2250113,"amplitude":0.695834},{"time":1.2290022,"amplitude":0.61917233},{"time":1.2340136,"amplitude":0.5880176},{"time":1.2370068,"amplitude":0.53021616},{"time":1.2410204,"amplitude":0.50928617},{"time":1.2450113,"amplitude":0.45255724},{"time":1.2500226,"amplitude":0.42614263},{"time":1.2540135,"amplitude":0.37573743},{"time":1.259025,"amplitude":0.35394874},{"time":1.2630159,"amplitude":0.3121782},{"time":1.2700226,"amplitude":0.28171903},{"time":1.2730159,"amplitude":0.25217998},{"time":1.2780045,"amplitude":0.23790987},{"time":1.2830158,"amplitude":0.2039585},{"time":1.3040136,"amplitude":0.13108838},{"time":1.3170068,"amplitude":0.09773624},{"time":1.3410203,"amplitude":0.057223924},{"time":1.3700227,"amplitude":0.028775413},{"time":1.399025,"amplitude":0.012871244},{"time":1.4290249,"amplitude":0.0040058647},{"time":1.4660317,"amplitude":0.00085569033},{"time":1.5120181,"amplitude":0.00051419035},{"time":1.7990476,"amplitude":0.00053922477},{"time":1.8,"amplitude":0.00053922477},{"time":1.8,"amplitude":0.00053922477}],"frequency":[{"time":0,"frequency":0.020718927},{"time":0.17414966,"frequency":0.0033238232},{"time":0.20897959,"frequency":0.09051466},{"time":0.21188208,"frequency":0.017611936},{"time":0.22349207,"frequency":0.36407393},{"time":0.22929706,"frequency":0.3733385},{"time":0.23510204,"frequency":1},{"time":0.28734693,"frequency":1},{"time":0.29315192,"frequency":0.03697985},{"time":0.3076644,"frequency":0.015080327},{"time":0.44408163,"frequency":0.0042551477},{"time":0.510839,"frequency":0.013670002},{"time":0.5195465,"frequency":0.114794515},{"time":0.528254,"frequency":1},{"time":0.6675737,"frequency":1},{"time":0.6704762,"frequency":0.39109683},{"time":0.6733787,"frequency":1},{"time":0.76335603,"frequency":1},{"time":0.7662585,"frequency":0.34064588},{"time":0.769161,"frequency":1},{"time":0.8126984,"frequency":1},{"time":0.8156009,"frequency":0.46277383},{"time":0.8185034,"frequency":1},{"time":0.8591383,"frequency":1},{"time":0.8620408,"frequency":0.33363342},{"time":0.8649433,"frequency":1},{"time":0.88816327,"frequency":1},{"time":0.8910658,"frequency":0.14180698},{"time":0.8939682,"frequency":0.029813504},{"time":0.9984581,"frequency":0.0049297404},{"time":1.0013604,"frequency":0.0075458325},{"time":1.0390929,"frequency":0.0169438},{"time":1.0594103,"frequency":0.0026711088},{"time":1.0942403,"frequency":0.010803959},{"time":1.1058502,"frequency":0.07026733},{"time":1.1116552,"frequency":0.18236092},{"time":1.1174603,"frequency":0.1253173},{"time":1.1203628,"frequency":0.028144006},{"time":1.1232653,"frequency":0.4114257},{"time":1.1261678,"frequency":1},{"time":1.1900226,"frequency":1},{"time":1.1929251,"frequency":0.04367737},{"time":1.2074375,"frequency":0.015173969},{"time":1.2974149,"frequency":0.0044053462},{"time":1.3264399,"frequency":0.013245664},{"time":1.3612697,"frequency":0.0032118666},{"time":1.3670747,"frequency":0.019418897},{"time":1.3873922,"frequency":0.0033809673},{"time":1.4077097,"frequency":0.009184113},{"time":1.4106121,"frequency":0.056718018},{"time":1.4193196,"frequency":0.050725304},{"time":1.4280272,"frequency":0.2703589},{"time":1.4309297,"frequency":1},{"time":1.4512471,"frequency":1},{"time":1.4541496,"frequency":0.22229218},{"time":1.4570521,"frequency":1},{"time":1.6457142,"frequency":1},{"time":1.6486167,"frequency":0.3691811},{"time":1.6515192,"frequency":1},{"time":1.7879364,"frequency":1}]}}}} \ No newline at end of file diff --git a/Assets/Resources/Haptics/NVHeartbeats.haptic.meta b/Assets/Resources/Haptics/NVHeartbeats.haptic.meta new file mode 100644 index 0000000..52e83ed --- /dev/null +++ b/Assets/Resources/Haptics/NVHeartbeats.haptic.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: fda7592f03fc841e382414b80b40df5b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: dc84fb4fa9e67485a972c887d976d004, type: 3} diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index e3f8118..17aec8f 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -192,7 +192,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: SetState(Game) + m_Text: SetState(Ice) --- !u!222 &17265521 CanvasRenderer: m_ObjectHideFlags: 0 @@ -280,6 +280,85 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 351150075} m_CullTransparentMesh: 1 +--- !u!1 &365736686 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 365736687} + - component: {fileID: 365736689} + - component: {fileID: 365736688} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &365736687 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 365736686} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1490886058} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &365736688 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 365736686} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &365736689 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 365736686} + m_CullTransparentMesh: 1 --- !u!1 &392790003 GameObject: m_ObjectHideFlags: 0 @@ -623,7 +702,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: SetState(Guitar) + m_Text: SetState(Cloud) --- !u!222 &519563563 CanvasRenderer: m_ObjectHideFlags: 0 @@ -863,6 +942,129 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 876276281} m_CullTransparentMesh: 1 +--- !u!1 &1013617498 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1013617500} + - component: {fileID: 1013617499} + m_Layer: 0 + m_Name: HapticSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1013617499 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1013617498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b1939bb20b5db46c1a5f7354ca0fba87, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1013617500 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1013617498} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 137.02786, y: 340.55707, z: -2.1220903} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1015854312 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1015854313} + - component: {fileID: 1015854315} + - component: {fileID: 1015854314} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1015854313 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1015854312} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1490886058} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1015854314 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1015854312} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Audio Object ID +--- !u!222 &1015854315 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1015854312} + m_CullTransparentMesh: 1 --- !u!1 &1161878325 GameObject: m_ObjectHideFlags: 0 @@ -999,6 +1201,341 @@ MonoBehaviour: m_EditorClassIdentifier: targetGameState: 0 enableLowpass: 0 +--- !u!1 &1193187742 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1193187743} + - component: {fileID: 1193187745} + - component: {fileID: 1193187744} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1193187743 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1193187742} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1371927793} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1193187744 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1193187742} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: PlaySound Direct +--- !u!222 &1193187745 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1193187742} + m_CullTransparentMesh: 1 +--- !u!1 &1371927792 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1371927793} + - component: {fileID: 1371927796} + - component: {fileID: 1371927795} + - component: {fileID: 1371927794} + - component: {fileID: 1371927798} + - component: {fileID: 1371927797} + m_Layer: 5 + m_Name: PlaySoundDirect + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1371927793 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371927792} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1193187743} + m_Father: {fileID: 1667985901} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 150, y: -608.3334} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1371927794 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371927792} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1371927795} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1371927798} + m_TargetAssemblyTypeName: UnityEngine.AudioSource, UnityEngine + m_MethodName: Play + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1371927797} + m_TargetAssemblyTypeName: PlaySoundBind, Assembly-CSharp + m_MethodName: OnButtonPressed + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1371927795 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371927792} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1371927796 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371927792} + m_CullTransparentMesh: 1 +--- !u!114 &1371927797 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371927792} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3bdbaddf2c05142e19686a9a82ef92c3, type: 3} + m_Name: + m_EditorClassIdentifier: + inputField: {fileID: 1490886059} +--- !u!82 &1371927798 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371927792} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: -1744738308437188463, guid: 11793d92750e64286bcdd6a61eeec520, type: 2} + m_audioClip: {fileID: 8300000, guid: 95f3e694b4c5b4892871f69fd96b4b7f, type: 3} + m_PlayOnAwake: 0 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 --- !u!1 &1394234347 GameObject: m_ObjectHideFlags: 0 @@ -1011,8 +1548,9 @@ GameObject: - component: {fileID: 1394234351} - component: {fileID: 1394234350} - component: {fileID: 1394234349} + - component: {fileID: 1394234352} m_Layer: 5 - m_Name: Button (Legacy) + m_Name: PlaySound m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -1082,16 +1620,16 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 2093584670} - m_TargetAssemblyTypeName: OCES.Audio.AudioSystem, Assembly-CSharp - m_MethodName: Play - m_Mode: 5 + - m_Target: {fileID: 1394234352} + m_TargetAssemblyTypeName: PlaySoundBind, Assembly-CSharp + m_MethodName: OnButtonPressed + m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 11 + m_IntArgument: 0 m_FloatArgument: 0 - m_StringArgument: rain + m_StringArgument: m_BoolArgument: 0 m_CallState: 2 --- !u!114 &1394234350 @@ -1132,6 +1670,165 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1394234347} m_CullTransparentMesh: 1 +--- !u!114 &1394234352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1394234347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3bdbaddf2c05142e19686a9a82ef92c3, type: 3} + m_Name: + m_EditorClassIdentifier: + inputField: {fileID: 1490886059} +--- !u!1 &1490886057 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1490886058} + - component: {fileID: 1490886061} + - component: {fileID: 1490886060} + - component: {fileID: 1490886059} + m_Layer: 5 + m_Name: InputField (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1490886058 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1490886057} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1015854313} + - {fileID: 365736687} + m_Father: {fileID: 1667985901} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1490886059 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1490886057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1490886060} + m_TextComponent: {fileID: 365736688} + m_Placeholder: {fileID: 1015854314} + m_ContentType: 2 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 2 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 1 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1490886060 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1490886057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1490886061 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1490886057} + m_CullTransparentMesh: 1 --- !u!1 &1542973982 GameObject: m_ObjectHideFlags: 0 @@ -1184,7 +1881,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 2ce47fe7df364a8fa37501256e5b5155, type: 3} m_Name: m_EditorClassIdentifier: - targetGameState: 4 + targetGameState: 2 enableLowpass: 0 --- !u!114 &1542973985 MonoBehaviour: @@ -1301,12 +1998,14 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1987857384} + - {fileID: 1490886058} - {fileID: 1394234348} - {fileID: 1161878326} - {fileID: 392790004} - {fileID: 1542973983} - {fileID: 876276282} - {fileID: 1989157233} + - {fileID: 1371927793} m_Father: {fileID: 619394802} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -1343,10 +2042,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 300, y: 666.666} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1395,7 +2094,7 @@ MonoBehaviour: m_Top: 0 m_Bottom: 0 m_ChildAlignment: 4 - m_Spacing: 15 + m_Spacing: 5 m_ChildForceExpandWidth: 0 m_ChildForceExpandHeight: 0 m_ChildControlWidth: 0 @@ -1473,7 +2172,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: PlaySond + m_Text: PlaySound --- !u!222 &1762080067 CanvasRenderer: m_ObjectHideFlags: 0 @@ -1620,7 +2319,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: SetState(Home) + m_Text: SetState(Normal) --- !u!222 &1798358789 CanvasRenderer: m_ObjectHideFlags: 0 @@ -1988,3 +2687,4 @@ SceneRoots: - {fileID: 619394802} - {fileID: 1777712068} - {fileID: 2093584671} + - {fileID: 1013617500} diff --git a/Assets/Scripts/Lofelt.meta b/Assets/Scripts/Lofelt.meta new file mode 100644 index 0000000..fb0ae43 --- /dev/null +++ b/Assets/Scripts/Lofelt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea1308527d88a4ad79766c4f2ef437bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations.meta b/Assets/Scripts/Lofelt/NiceVibrations.meta new file mode 100644 index 0000000..7f8c92a --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dbba4d66508f04365a91f3b7eb67d2f3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components.meta new file mode 100644 index 0000000..6e9457f --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 688d27f50942c40c39cb42dc1e5eab7a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/AssemblyInfo.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/AssemblyInfo.cs new file mode 100644 index 0000000..0cac064 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/AssemblyInfo.cs @@ -0,0 +1,3 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("NiceVibrationTests")] \ No newline at end of file diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/AssemblyInfo.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/AssemblyInfo.cs.meta new file mode 100644 index 0000000..2a79def --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0924103a050c4bbc88d415b79a67df2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/DeviceCapabilities.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/DeviceCapabilities.cs new file mode 100644 index 0000000..0e7c6b5 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/DeviceCapabilities.cs @@ -0,0 +1,253 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using UnityEngine; + +#if (UNITY_IOS && !UNITY_EDITOR) + using UnityEngine.iOS; +#endif + +namespace Lofelt.NiceVibrations +{ + /// + /// A class containing properties that describe the current device capabilities for use with + /// Nice Vibrations + /// + /// + /// This class describes the capabilities of an iOS or Android device, gamepads are not handled + /// by it. + public static class DeviceCapabilities + { + /// + /// Property that holds the current RuntimePlatform + /// + public static RuntimePlatform platform { get; } + + /// + /// Property that holds the current platform version. + /// + /// iOS version on iOS, Android API level on Android or 0 otherwise. + public static int platformVersion { get; } + + /// + /// Indicates if the device meets the requirements to play advanced haptics with + /// Nice Vibrations + /// + /// + /// Advanced requirements means that the device can play back .haptic clips. + /// While devices that don't meet the advanced requirements can not play back .haptic + /// clips, they can still play back simpler fallback haptics as long as + /// \ref isVersionSupported is true. + /// + /// While DeviceCapabilities.isVersionSupported only checks the OS version, this method + /// additionally checks the device capabilities. + /// + /// The required device capabilities are: + /// - iOS: iPhone >= 8 + /// - Android: Amplitude control for the Vibrator + /// + /// You don't usually need to check this property. All other methods in HapticController + /// will check \ref meetsAdvancedRequirements before calling into LofeltHaptics. + /// In case the device does not support advanced haptics there is a possibility of fallback + /// haptics based on presets. + public static bool meetsAdvancedRequirements + { + get + { + return _meetsAdvancedRequirements; + } + } + private static bool _meetsAdvancedRequirements; + + /// + /// Indicates if the OS version is high enough to play haptics with Nice Vibrations. + /// + /// + /// The minimum required versions are: + /// - iOS >= 11 + /// - Android API level >= 17 + /// + /// This only checks the minimum supported OS version in terms of API and does not guarantee + /// that advanced haptics with amplitude control can be recreated, For that check with + /// \ref meetsAdvancedRequirements. + public static bool isVersionSupported { get; } + + /// + /// Indicates if the device is capable of amplitude control in order to recreate + /// advanced haptics. + /// + public static bool hasAmplitudeControl + { + get + { + return _hasAmplitudeControl; + } + } + private static bool _hasAmplitudeControl; + + /// + /// Indicates if the device is capable of changing the frequency of haptic signals + /// + public static bool hasFrequencyControl + { + get + { + return _hasFrequencyControl; + } + } + private static bool _hasFrequencyControl; + + /// + /// Indicates if the device is capable of real-time amplitude modulation of haptic signals + /// + public static bool hasAmplitudeModulation + { + get + { + return _hasAmplitudeModulation; + } + } + private static bool _hasAmplitudeModulation; + + /// + /// Indicates if the device is capable of real-time frequency modulation of haptic signals + /// + public static bool hasFrequencyModulation + { + get + { + return _hasFrequencyModulation; + } + } + private static bool _hasFrequencyModulation; + + /// + /// Indicates if the device is capable of natively reproducing emphasized haptics + /// + public static bool hasEmphasis + { + get + { + return _hasEmphasis; + } + } + private static bool _hasEmphasis; + + /// + /// Indicates if the device is capable of emulating emphasized haptics + /// + public static bool canEmulateEmphasis + { + get + { + return _canEmulateEmphasis; + } + } + private static bool _canEmulateEmphasis; + + /// + /// Indicates if the device is capable of looping haptic clips + /// + public static bool canLoop + { + get + { + return _canLoop; + } + } + private static bool _canLoop; + + /// + /// Constructor that fills in the only the DeviceCapabilities platform version properties. + /// + /// This is separate of Init() because we need to first check the version numbers before + /// initializing LofeltHaptics + static DeviceCapabilities() + { + platform = Application.platform; + platformVersion = 0; + isVersionSupported = false; + +#if (UNITY_ANDROID && !UNITY_EDITOR) + platformVersion = int.Parse(SystemInfo.operatingSystem.Substring(SystemInfo.operatingSystem.IndexOf("-") + 1, 3)); + const int minimumSupportedAndroidSDKVersion = 17; + isVersionSupported = platformVersion >= minimumSupportedAndroidSDKVersion; +#elif (UNITY_IOS && !UNITY_EDITOR) + string versionString = Device.systemVersion; + string[] versionArray = versionString.Split('.'); + platformVersion = int.Parse(versionArray[0]); + const int minimumSupportedIOSVersion = 11; + isVersionSupported = platformVersion >= minimumSupportedIOSVersion; + + DeviceGeneration generation = Device.generation; + if ((generation == DeviceGeneration.iPhone3G) + || (generation == DeviceGeneration.iPhone3GS) + || (generation == DeviceGeneration.iPodTouch1Gen) + || (generation == DeviceGeneration.iPodTouch2Gen) + || (generation == DeviceGeneration.iPodTouch3Gen) + || (generation == DeviceGeneration.iPodTouch4Gen) + || (generation == DeviceGeneration.iPhone4) + || (generation == DeviceGeneration.iPhone4S) + || (generation == DeviceGeneration.iPhone5) + || (generation == DeviceGeneration.iPhone5C) + || (generation == DeviceGeneration.iPhone5S) + || (generation == DeviceGeneration.iPhone6) + || (generation == DeviceGeneration.iPhone6Plus) + || (generation == DeviceGeneration.iPhone6S) + || (generation == DeviceGeneration.iPhone6SPlus) + || (generation == DeviceGeneration.iPhoneSE1Gen) + || (generation == DeviceGeneration.iPad1Gen) + || (generation == DeviceGeneration.iPad2Gen) + || (generation == DeviceGeneration.iPad3Gen) + || (generation == DeviceGeneration.iPad4Gen) + || (generation == DeviceGeneration.iPad5Gen) + || (generation == DeviceGeneration.iPadAir1) + || (generation == DeviceGeneration.iPadAir2) + || (generation == DeviceGeneration.iPadMini1Gen) + || (generation == DeviceGeneration.iPadMini2Gen) + || (generation == DeviceGeneration.iPadMini3Gen) + || (generation == DeviceGeneration.iPadMini4Gen) + || (generation == DeviceGeneration.iPadPro10Inch1Gen) + || (generation == DeviceGeneration.iPadPro10Inch2Gen) + || (generation == DeviceGeneration.iPadPro11Inch) + || (generation == DeviceGeneration.iPadPro1Gen) + || (generation == DeviceGeneration.iPadPro2Gen) + || (generation == DeviceGeneration.iPadPro3Gen) + || (generation == DeviceGeneration.iPadUnknown) + || (generation == DeviceGeneration.iPodTouch1Gen) + || (generation == DeviceGeneration.iPodTouch2Gen) + || (generation == DeviceGeneration.iPodTouch3Gen) + || (generation == DeviceGeneration.iPodTouch4Gen) + || (generation == DeviceGeneration.iPodTouch5Gen) + || (generation == DeviceGeneration.iPodTouch6Gen) + || (generation == DeviceGeneration.iPhone6SPlus)) + { + isVersionSupported = false; + } + +#elif (UNITY_EDITOR) + isVersionSupported = true; +#endif + } + + /// + /// Function that initializes the rest of the DeviceCapabilities properties. + /// Must be called after LofeltHaptics was initialized. + /// + public static void Init() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + _hasAmplitudeControl = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + _canEmulateEmphasis = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + _canLoop = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); +#elif (UNITY_IOS && !UNITY_EDITOR) + _hasAmplitudeControl = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + _hasFrequencyControl = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + _hasAmplitudeModulation = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + _hasFrequencyModulation = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + _hasEmphasis = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + _canLoop = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); +#endif + _meetsAdvancedRequirements = LofeltHaptics.DeviceMeetsMinimumPlatformRequirements(); + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/DeviceCapabilities.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/DeviceCapabilities.cs.meta new file mode 100644 index 0000000..715c644 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/DeviceCapabilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca68228d4301d47fab6a64b6d285e2dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Gamepad.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/Gamepad.cs new file mode 100644 index 0000000..e700ce3 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Gamepad.cs @@ -0,0 +1,435 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using System; +using System.Diagnostics; +using System.Timers; +using UnityEngine; + +// There are 3 conditions for working gamepad support in Nice Vibrations: +// +// 1. NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED - The input system package needs to be installed. +// See https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Installation.html#installing-the-package +// This is set by Nice Vibrations' assembly definition file, using a version define. +// See https://docs.unity3d.com/Manual/ScriptCompilationAssemblyDefinitionFiles.html#define-symbols +// about version defines, and see Lofelt.NiceVibrations.asmdef for the usage in Nice Vibrations. +// +// 2. ENABLE_INPUT_SYSTEM - The input system needs to be enabled in the project settings. +// See https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Installation.html#enabling-the-new-input-backends +// This define is set by Unity, see https://docs.unity3d.com/Manual/PlatformDependentCompilation.html +// +// 3. NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT - This is a user-defined define which needs to be not set. +// NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT is not set by default. It can be set by a user in the +// player settings to disable gamepad support completely. One reason to do this is to reduce the +// size of a HapticClip asset, as setting this define changes to HapticImporter to not add the +// GamepadRumble to the HapticClip. Changing this define requires re-importing all .haptic clip +// assets to update HapticClip's GamepadRumble. +// +// If any of the 3 conditions is not met, GamepadRumbler doesn't contain any calls into +// UnityEngine.InputSystem, and CanPlay() always returns false. +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT +using UnityEngine.InputSystem; +#endif + +namespace Lofelt.NiceVibrations +{ + /// + /// Contains a vibration pattern to make a gamepad rumble. + /// + /// + /// GamepadRumble contains the information on when to set what motor speeds on a gamepad + /// to make it rumble with a specific pattern. + /// + /// GamepadRumble has three arrays of the same length representing the rumble pattern. The + /// entries for each array index describe for how long to turn on the gamepad's vibration + /// motors, at what speed. + [Serializable] + public struct GamepadRumble + { + /// + /// The duration, in milliseconds, that the motors will be turned on at the speed set + /// in \ref lowFrequencyMotorSpeeds and \ref highFrequencyMotorSpeeds at the same array + /// index + /// + [SerializeField] + public int[] durationsMs; + + /// + /// The total duration of the GamepadRumble, in milliseconds + /// + [SerializeField] + public int totalDurationMs; + + /// + /// The motor speeds of the low frequency motor + /// + [SerializeField] + public float[] lowFrequencyMotorSpeeds; + + /// + /// The motor speeds of the high frequency motor + /// + [SerializeField] + public float[] highFrequencyMotorSpeeds; + + /// + /// Checks if the GamepadRumble is valid and also not empty + /// + /// Whether the GamepadRumble is valid + public bool IsValid() + { + return durationsMs != null && + lowFrequencyMotorSpeeds != null && + highFrequencyMotorSpeeds != null && + durationsMs.Length == lowFrequencyMotorSpeeds.Length && + durationsMs.Length == highFrequencyMotorSpeeds.Length && + durationsMs.Length > 0; + } + } + + /// + /// Vibrates a gamepad based on a GamepadRumble rumble pattern. + /// + /// + /// GamepadRumbler can load and play back a GamepadRumble pattern on the current + /// gamepad. + /// + /// This is a low-level class that normally doesn't need to be used directly. Instead, + /// you can use HapticSource and HapticController to play back haptic clips, as those + /// classes support gamepads by using GamepadRumbler internally. + public static class GamepadRumbler + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + static GamepadRumble loadedRumble; + + static bool rumbleLoaded = false; + + // This Timer is used to wait until it is time to advance to the next entry in loadedRumble. + // When the Timer is elapsed, ProcessNextRumble() is called to set new motor speeds to the + // gamepad. + static Timer rumbleTimer = new Timer(); + + // The index of the entry of loadedRumble that is currently being played back + static int rumbleIndex = -1; + + // The total duration of rumble entries that have been played back so far + static long rumblePositionMs = 0; + + // Keeps track of how much time elapsed since playback was started + static Stopwatch playbackWatch = new Stopwatch(); + + /// + /// A multiplication factor applied to the motor speeds of the low frequency motor. + /// + /// + /// The multiplication factor is applied to the low frequency motor speed of every + /// GamepadRumble entry before playing it. + /// + /// In other words, this applies a gain (for factors greater than 1.0) or an attenuation + /// (for factors less than 1.0) to the clip. If the resulting speed of an entry is + /// greater than 1.0, it is clipped to 1.0. The speed is clipped hard, no limiter is + /// used. + /// + /// The motor speed multiplication is reset when calling Load(), so Load() needs to be + /// called first before setting the multiplication. + /// + /// A change of the multiplication is applied to a currently playing rumble, but only + /// for the next rumble entry, not the one currently playing. + public static float lowFrequencyMotorSpeedMultiplication = 1.0f; + + /// + /// Same as \ref lowFrequencyMotorSpeedMultiplication, but for the high frequency speed + /// motor. + /// + public static float highFrequencyMotorSpeedMultiplication = 1.0f; + + static int currentGamepadID = -1; + +#endif + + /// + /// Initializes the GamepadRumbler. + /// + /// + /// This needs to be called from the main thread, which is the reason why this is a method + /// instead of a static constructor: Sometimes Unity calls static constructors from a + /// different thread, and an explicit Init() method gives us more control over this. + public static void Init() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + // Initialize rumbleTimer, so that ProcessNextRumble() will be called on the main thread + // when the timer is triggered. + var syncContext = System.Threading.SynchronizationContext.Current; + rumbleTimer.Elapsed += (object obj, System.Timers.ElapsedEventArgs args) => + { + syncContext.Post(_ => + { + ProcessNextRumble(); + }, null); + }; +#endif + } + + /// + /// Checks whether a call to Play() would trigger playback on a gamepad. + /// + /// + /// Playing back a rumble pattern with Play() only works if a gamepad is connected and if + /// a GamepadRumble has been loaded with Load() before. + /// + /// Whether a vibration can be triggered on a gamepad + public static bool CanPlay() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + return IsConnected() && rumbleLoaded && loadedRumble.IsValid(); +#else + return false; +#endif + } + +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + /// + /// Gets the Gamepad object corresponding to the specified gamepad ID. + /// + /// + /// If the specified ID is out of range of the connected gamepad(s), + /// InputSystem.Gamepad.current will be returned. + /// + /// The ID of the gamepad to be returned. + /// A InputSystem.Gamepad + static UnityEngine.InputSystem.Gamepad GetGamepad(int gamepadID) + { + if (gamepadID >= 0) + { + if (gamepadID >= UnityEngine.InputSystem.Gamepad.all.Count) + { + return UnityEngine.InputSystem.Gamepad.current; + } + else + { + return UnityEngine.InputSystem.Gamepad.all[gamepadID]; + } + } + return UnityEngine.InputSystem.Gamepad.current; + } +#endif + + /// + /// Set the current gamepad for haptics playback by ID. + /// + /// + /// This method needs be called before haptics playback, e.g. \ref HapticController.Play(), + /// \ref HapticPatterns.PlayEmphasis(), \ref HapticPatterns.PlayConstant(), etc, for + /// for the gamepad to be properly selected. + /// + /// If this method isn't called, haptics will be played on InputSystem.Gamepad.current + /// + /// For example, if you have 3 controllers connected, you have to choose between values 0, 1, + /// and 2. + /// + /// If the gamepad ID value doesn't match any connected gamepad, calling + /// this method has no effect. + /// The ID of the gamepad + public static void SetCurrentGamepad(int gamepadID) + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + if (gamepadID < UnityEngine.InputSystem.Gamepad.all.Count) + { + currentGamepadID = gamepadID; + } +#endif + } + + /// + /// Checks whether a gamepad is connected and recognized by Unity's input system. + /// + /// + /// If the input system package is not installed or not enabled, the gamepad is not + /// recognized and treated as not connected here. + /// + /// If the NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT define is set in the player settings, + /// this function pretends no gamepad is connected. + /// + /// Whether a gamepad is connected + public static bool IsConnected() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + return GetGamepad(currentGamepadID) != null; +#else + return false; +#endif + } + + /// + /// Loads a rumble pattern for later playback. + /// + /// + /// The rumble pattern to load + public static void Load(GamepadRumble rumble) + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + if (rumble.IsValid()) + { + loadedRumble = rumble; + rumbleLoaded = true; + lowFrequencyMotorSpeedMultiplication = 1.0f; + highFrequencyMotorSpeedMultiplication = 1.0f; + } + else + { + Unload(); + } +#endif + } + + /// + /// Plays back the rumble pattern loaded previously with Load(). + /// + /// + /// If no rumble pattern has been loaded, or if no gamepad is connected, this method does + /// nothing. + public static void Play() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + if (CanPlay()) + { + rumbleIndex = 0; + rumblePositionMs = 0; + playbackWatch.Restart(); + ProcessNextRumble(); + } +#endif + } + + /// + /// Stops playback previously started with Play() by turning off the gamepad's motors. + /// + public static void Stop() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + if (GetGamepad(currentGamepadID) != null) + { + GetGamepad(currentGamepadID).ResetHaptics(); + } + rumbleTimer.Enabled = false; + rumbleIndex = -1; + rumblePositionMs = 0; + playbackWatch.Stop(); +#endif + } + + /// + /// Stops playback and unloads the currently loaded GamepadRumble from memory. + /// + public static void Unload() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + loadedRumble.highFrequencyMotorSpeeds = null; + loadedRumble.lowFrequencyMotorSpeeds = null; + loadedRumble.durationsMs = null; + rumbleLoaded = false; + Stop(); +#endif + } + + // Advances the position in the GamepadRumble by one. + // + // If the end of the rumble has been reached, playback is stopped and false is returned. + private static bool IncreaseRumbleIndex() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + rumblePositionMs += loadedRumble.durationsMs[rumbleIndex]; + rumbleIndex++; + if (rumbleIndex == loadedRumble.durationsMs.Length) + { + Stop(); + return false; + } + + return true; +#else + return false; +#endif + } + + // Processes the next entry in loadedRumble by setting the gamepad's motor speeds to the + // speeds stored in that entry. + // + // Afterwards, the rumbleTimer is set to call this method again, after the time stored + // in entry of loadedRumble. + private static void ProcessNextRumble() + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + // rumbleIndex can be -1 after Stop() has been called after the call to + // ProcessNextRumble() has already been queued up via SynchronizationContext. + if (rumbleIndex == -1) + { + return; + } + + if (rumbleIndex == loadedRumble.durationsMs.Length) + { + Stop(); + return; + } + + UnityEngine.Debug.Assert(loadedRumble.IsValid()); + UnityEngine.Debug.Assert(rumbleLoaded); + UnityEngine.Debug.Assert(rumbleIndex >= 0 && rumbleIndex <= loadedRumble.durationsMs.Length); + + // Figure out for how long the current rumble entry should be played (durationToWait). + // Due to the timer not waiting for exactly the same amount of time that we requested, + // there can be a bit of error that we need to compensate for. For example, if the timer + // waited for 3ms longer than we requested, we play the next rumble entry for a 3ms + // less to compensate for that. + // In fact, Unity triggers the timer only once per frame, so at 30 FPS, the timer + // resolution is 32ms. That means that the timing error can be bigger than the duration + // of the whole rumble entry, and to compensate for that, the entire rumble entry needs + // to be skipped. That's what the loop does: It skips rumble entries to compensate for + // timer error. + long elapsed = playbackWatch.ElapsedMilliseconds; + long durationToWait = 0; + while (true) + { + long rumbleEntryDuration = loadedRumble.durationsMs[rumbleIndex]; + long error = elapsed - rumblePositionMs; + durationToWait = rumbleEntryDuration - error; + + // If durationToWait is <= 0, the current rumble entry needs to be skipped to + // compensate for timer error. Otherwise break and play the current rumble entry. + if (durationToWait > 0) + { + break; + } + + // If the end of the rumble has been reached, return, as playback has stopped. + if (!IncreaseRumbleIndex()) + { + return; + } + } + + float lowFrequencySpeed = loadedRumble.lowFrequencyMotorSpeeds[rumbleIndex] * Mathf.Max(lowFrequencyMotorSpeedMultiplication, 0.0f); + float highFrequencySpeed = loadedRumble.highFrequencyMotorSpeeds[rumbleIndex] * Mathf.Max(highFrequencyMotorSpeedMultiplication, 0.0f); + + UnityEngine.InputSystem.Gamepad currentGamepad = GetGamepad(currentGamepadID); + // Check if gamepad was disconnected while playing + if (currentGamepad != null) + { + currentGamepad.SetMotorSpeeds(lowFrequencySpeed, highFrequencySpeed); + } + else + { + return; + } + + // Set up the timer to call ProcessNextRumble() again with the next rumble entry, after + // the duration of the current rumble entry. + rumblePositionMs += loadedRumble.durationsMs[rumbleIndex]; + rumbleIndex++; + rumbleTimer.Interval = durationToWait; + rumbleTimer.AutoReset = false; + rumbleTimer.Enabled = true; +#endif + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Gamepad.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Gamepad.cs.meta new file mode 100644 index 0000000..3459d00 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Gamepad.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef20247bd5f04449293bb8ea3982f3ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticClip.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticClip.cs new file mode 100644 index 0000000..0f3705a --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticClip.cs @@ -0,0 +1,35 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using UnityEngine; + +namespace Lofelt.NiceVibrations +{ + /// + /// Represents an imported haptic clip asset. + /// + /// + /// HapticClip contains the data of a haptic clip asset imported from a .haptic file, + /// in a format suitable for playing it back at runtime. + /// A HapticClip is created by HapticImporter when importing a haptic clip asset + /// in the Unity editor, and can be played back at runtime with e.g. HapticSource or + /// HapticController::Play(). + /// + /// It contains two representations: + /// - JSON, used for playback on iOS and Android + /// - GamepadRumble, used for playback on gamepads with the GamepadRumbler class + public class HapticClip : ScriptableObject + { + /// + /// The JSON representation of the haptic clip, stored as a byte array encoded in UTF-8, + /// without a null terminator + /// + [SerializeField] + public byte[] json; + + /// + /// The haptic clip represented as a GamepadRumble struct + /// + [SerializeField] + public GamepadRumble gamepadRumble; + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticClip.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticClip.cs.meta new file mode 100644 index 0000000..8768c72 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticClip.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df8d044f677634e749812dc987300584 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticController.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticController.cs new file mode 100644 index 0000000..4a586f3 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticController.cs @@ -0,0 +1,568 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using UnityEngine; +using System; +using System.Timers; + +#if (UNITY_ANDROID && !UNITY_EDITOR) +using System.Text; +#elif (UNITY_IOS && !UNITY_EDITOR) +using UnityEngine.iOS; +#endif + +namespace Lofelt.NiceVibrations +{ + /// + /// Provides haptic playback functionality. + /// + /// + /// HapticController allows you to load and play .haptic clips, and + /// provides various ways to control playback, such as seeking, looping and + /// amplitude/frequency modulation. + /// + /// If you need a MonoBehaviour API, use HapticSource and + /// HapticReceiver instead. + /// + /// On iOS and Android, the device is vibrated, using LofeltHaptics. + /// On any platform, when a gamepad is connected, that gamepad is vibrated, + /// using GamepadRumbler. + /// + /// Gamepads are vibrated automatically when HapticController detects that a + /// gamepad is connected, no special code is needed to support gamepads. + /// Gamepads only support Load(), Play(), Stop(), \ref clipLevel and \ref + /// outputLevel. Other features like Seek(), Loop() and \ref clipFrequencyShift + /// will have no effect on gamepads. + /// + /// None of the methods here are thread-safe and should only be called from + /// the main (Unity) thread. Calling these methods from a secondary thread can + /// cause undefined behaviour and memory leaks. + public static class HapticController + { + static bool lofeltHapticsInitalized = false; + + // Timer used to call HandleFinishedPlayback() when playback is complete + static Timer playbackFinishedTimer = new Timer(); + + // Duration of the loaded haptic clip, in seconds + static float clipLoadedDurationSecs = 0.0f; + + // Whether Load() has been called before + static bool clipLoaded = false; + + // The value of the last call to seek() + static float lastSeekTime = 0.0f; + + // Flag indicating if the device supports playing back .haptic clips + static bool deviceMeetsAdvancedRequirements = false; + + // Flag indicating if the user enabled playback looping. + // This does not necessarily mean that the currently active playback is looping, for + // example gamepads don't support looping. + static bool isLoopingEnabledByUser = false; + + // Flag indicating if the currently active playback is looping + static bool isPlaybackLooping = false; + + static HapticPatterns.PresetType _fallbackPreset = HapticPatterns.PresetType.None; + + /// + /// The haptic preset to be played when it's not possible to play a haptic clip + /// + public static HapticPatterns.PresetType fallbackPreset + { + get { return _fallbackPreset; } + set { _fallbackPreset = value; } + } + + internal static bool _hapticsEnabled = true; + + /// + /// Property to enable and disable global haptic playback + /// + public static bool hapticsEnabled + { + get { return _hapticsEnabled; } + set + { + if (_hapticsEnabled) + { + Stop(); + } + _hapticsEnabled = value; + } + } + + internal static float _outputLevel = 1.0f; + + /// + /// The overall haptic output level + /// + /// + /// It can be interpreted as the "volume control" for haptic playback. + /// Output level is applied in combination with \ref clipLevel to the currently playing haptic clip. + /// The combination of these two levels and the amplitude within the loaded haptic at a given moment + /// in time determines the strength of the vibration felt on the device. \ref outputLevel is best used + /// to increase or decrease the overall haptic level in a game. + /// + /// As output level pertains to all clips, unlike \ref clipLevel, it persists when a new clip is loaded. + /// + /// \ref outputLevel is a multiplication factor, it is not a dB value. The factor needs to be + /// 0 or greater. + /// + /// The combination of \ref outputLevel and \ref clipLevel can result in a gain (for factors + /// greater than 1.0) or an attenuation (for factors less than 1.0) to the clip. If the + /// combination of \ref outputLevel, \ref clipLevel and the amplitude within the loaded haptic + /// is greater than 1.0, it is clipped to 1.0. Hard clipping is performed, no limiter is used. + /// + /// On Android, an adjustment to \ref outputLevel will take effect in the next call to Play(). + /// On iOS, it will take effect right away. + [System.ComponentModel.DefaultValue(1.0f)] + public static float outputLevel + { + get { return _outputLevel; } + set + { + _outputLevel = value; + + ApplyLevelsToLofeltHaptics(); + ApplyLevelsToGamepadRumbler(); + } + } + + internal static float _clipLevel = 1.0f; + + /// + /// The level of the loaded clip + /// + /// + /// Clip level is applied in combination with \ref outputLevel, to the + /// currently playing haptic clip. The combination of these two levels and the amplitude within the loaded + /// haptic at a given moment in time determines the strength of the vibration felt on the device. + /// \ref clipLevel is best used to adjust the level of a single clip based on game state. + /// + /// As clip level is specific to an individual clip, unlike \ref outputLevel, it resets to + /// 1.0 when a new clip is loaded. + /// + /// \ref clipLevel is a multiplication factor, it is not a dB value. The factor needs to be + /// 0 or greater. + /// + /// The combination of \ref outputLevel and \ref clipLevel can result in a gain (for factors + /// greater than 1.0) or an attenuation (for factors less than 1.0) to the clip. + /// + /// If the combination of \ref outputLevel, \ref clipLevel and the amplitude within the loaded + /// haptic is greater than 1.0, it is clipped to 1.0. Hard clipping is performed, no limiter is used. + /// + /// The clip needs to be loaded with Load() before adjusting \ref clipLevel. Loading a clip + /// resets \ref clipLevel back to the default of 1.0. + /// + /// On Android, an adjustment to \ref clipLevel will take effect in the next call to Play(). On iOS, + /// it will take effect right away. + /// + /// On Android, setting the clip level should be done before calling \ref Seek(), since + /// setting a clip level ignores the sought value. + /// + [System.ComponentModel.DefaultValue(1.0f)] + public static float clipLevel + { + get { return _clipLevel; } + set + { + _clipLevel = value; + + ApplyLevelsToLofeltHaptics(); + ApplyLevelsToGamepadRumbler(); + } + } + + /// Action that is invoked when Load() is called + public static Action LoadedClipChanged; + + /// Action that is invoked when Play() is called + public static Action PlaybackStarted; + + /// + /// Action that is invoked when the playback has finished + /// + /// + /// This happens either when Stop() is explicitly called, or when a non-looping + /// clip has finished playing. + /// + /// This can be invoked spuriously, even if no haptics are currently playing, for example + /// if Stop() is called multiple times in a row. + public static Action PlaybackStopped; + + // Applies the current clip level and output level as the amplitude multiplication to + // LofeltHaptics + private static void ApplyLevelsToLofeltHaptics() + { + if (Init()) + { + LofeltHaptics.SetAmplitudeMultiplication(_outputLevel * _clipLevel); + } + } + + // Applies the current clip level and output level as the motor speed multiplication to + // GamepadRumbler + private static void ApplyLevelsToGamepadRumbler() + { + #if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + GamepadRumbler.lowFrequencyMotorSpeedMultiplication = _outputLevel * _clipLevel; + GamepadRumbler.highFrequencyMotorSpeedMultiplication = _outputLevel * _clipLevel; + #endif + } + + /// + /// Initializes HapticController. + /// + /// + /// Calling this method multiple times has no effect and is safe. + /// + /// You do not need to call this method, HapticController automatically calls this + /// method before any operation that needs initialization, such as Play(). + /// However it can be beneficial to call this early during startup, so the initialization + /// time is spent at startup instead of when the first haptic is triggered during gameplay. + /// If you have a HapticReceiver in your scene, it takes care of calling + /// Init() during startup for you. + /// + /// Do not call this method from a static constructor. Unity often invokes static + /// constructors from a different thread, for example during deserialization. The + /// initialization code is not thread-safe. This is the reason this method is not called + /// from the static constructor of HapticController or HapticReceiver. + /// + /// Whether the device supports the minimum requirements to play haptics + public static bool Init() + { + if (!lofeltHapticsInitalized) + { + lofeltHapticsInitalized = true; + + var syncContext = System.Threading.SynchronizationContext.Current; + playbackFinishedTimer.Elapsed += (object obj, System.Timers.ElapsedEventArgs args) => + { + // Timer elapsed events are called from a separate thread, so use + // SynchronizationContext to handle it in the main thread. + syncContext.Post(_ => + { + HandleFinishedPlayback(); + }, null); + }; + + if (DeviceCapabilities.isVersionSupported) + { + LofeltHaptics.Initialize(); + DeviceCapabilities.Init(); + deviceMeetsAdvancedRequirements = DeviceCapabilities.meetsAdvancedRequirements; + } + + GamepadRumbler.Init(); + } + return deviceMeetsAdvancedRequirements; + } + + /// + /// Loads a haptic clip given in JSON format for later playback. + /// + /// + /// This overload of Load() is useful in cases there is only the JSON data of a haptic clip + /// available. Due to only having the JSON data and no GamepadRumble, gamepad playback is + /// not supported with this overload. + /// + /// The haptic clip, which is the content of the + /// .haptic file, a UTF-8 encoded JSON string without a null + /// terminator + public static void Load(byte[] data) + { + GamepadRumbler.Unload(); + lastSeekTime = 0.0f; + clipLoaded = true; + clipLoadedDurationSecs = 0.0f; + if (Init()) + { + LofeltHaptics.Load(data); + } + clipLevel = 1.0f; + LoadedClipChanged?.Invoke(); + } + + /// + /// Loads the given HapticClip for later playback. + /// + /// + /// This is the standard way to load a haptic clip, while the other overloads of Load() + /// are for more specialized cases. + /// + /// At the moment only one clip can be loaded at a time. + /// + /// The HapticClip to be loaded + public static void Load(HapticClip clip) + { + Load(clip.json, clip.gamepadRumble); + } + + /// + /// Loads the haptic clip given as JSON and GamepadRumble for later playback. + /// + /// + /// This is an overload of Load() that is useful when a HapticClip is not available, and + /// both the JSON and GamepadRumble are. One such case is generating both dynamically at + /// runtime. + /// + /// The haptic clip, which is the content of the .haptic file, + /// a UTF-8 encoded JSON string without a null terminator + /// The GamepadRumble representation of the haptic clip + public static void Load(byte[] json, GamepadRumble rumble) + { + Load(json); + + GamepadRumbler.Load(rumble); + // GamepadRumbler.Load() resets the motor speed multiplication to 1.0, so the levels + // need to be applied here again + ApplyLevelsToGamepadRumbler(); + + // Load() only sets the correct clip duration on iOS and Android, and sets it to 0.0 + // on other platforms. For the other platforms, set a clip duration based on the + // GamepadRumble here. + if (clipLoadedDurationSecs == 0.0f && rumble.IsValid()) + { + clipLoadedDurationSecs = rumble.totalDurationMs / 1000.0f; + } + } + + static void HandleFinishedPlayback() + { + lastSeekTime = 0.0f; + isPlaybackLooping = false; + playbackFinishedTimer.Enabled = false; + PlaybackStopped?.Invoke(); + } + + /// + /// Plays the haptic clip that was previously loaded with Load(). + /// + /// + /// If Loop(true) was called previously, the playback will be repeated + /// until Stop() is called. Otherwise the haptic clip will only play once. + /// + /// In case the device does not meet the requirements to play .haptic clips, this + /// function will call HapticPatterns.PlayPreset() with the \ref fallbackPreset set. In this + /// case, functionality like seeking, looping and runtime modulation won't do anything as + /// they aren't available for haptic presets. + public static void Play() + { + if (!_hapticsEnabled) + { + return; + } + + float remainingPlayDuration = 0.0f; + bool canLoop = false; + if (GamepadRumbler.CanPlay()) + { + remainingPlayDuration = clipLoadedDurationSecs; + GamepadRumbler.Play(); + } + else if (Init()) + { + remainingPlayDuration = Mathf.Max(clipLoadedDurationSecs - lastSeekTime, 0.0f); + canLoop = DeviceCapabilities.canLoop; + LofeltHaptics.Play(); + } + else if (DeviceCapabilities.isVersionSupported) + { + remainingPlayDuration = HapticPatterns.GetPresetDuration(fallbackPreset); + HapticPatterns.PlayPreset(fallbackPreset); + } + + isPlaybackLooping = isLoopingEnabledByUser && canLoop; + PlaybackStarted?.Invoke(); + + // + // Call HandleFinishedPlayback() after the playback finishes + // + if (remainingPlayDuration > 0.0f) + { + playbackFinishedTimer.Interval = remainingPlayDuration * 1000; + playbackFinishedTimer.AutoReset = false; + playbackFinishedTimer.Enabled = !isPlaybackLooping; + } + else + { + // Setting playbackFinishedTimer.Interval needs an interval > 0, otherwise it will + // throw an exception. + // Even if the remaining play duration is 0, we still want to trigger everything + // that happens in HandleFinishedPlayback(). + // A playback duration of 0 happens in the Unity editor, when loading the clip + // failed or when seeking to the end of a clip. + HandleFinishedPlayback(); + } + } + + + /// + /// Loads and plays the HapticClip given as an argument. + /// + /// + /// The HapticClip to be played + public static void Play(HapticClip clip) + { + Load(clip); + Play(); + } + + /// + /// Stops haptic playback + /// + /// + public static void Stop() + { + + if (Init()) + { + LofeltHaptics.Stop(); + } + else + { + LofeltHaptics.StopPattern(); + } + GamepadRumbler.Stop(); + HandleFinishedPlayback(); + } + + /// + /// Jumps to a time position in the haptic clip. + /// + /// + /// The playback will always be stopped when this function is called. + /// This is to match the behavior between iOS and Android, since Android needs to + /// restart playback for seek to have effect. + /// + /// If seeking beyond the end of the clip, Play() will not reproduce any haptics. + /// Seeking to a negative position will seek to the beginning of the clip. + /// + /// The new position within the clip, as seconds from the beginning + /// of the clip + public static void Seek(float time) + { + if (Init()) + { + LofeltHaptics.Stop(); + LofeltHaptics.Seek(time); + } + GamepadRumbler.Stop(); + lastSeekTime = time; + } + + /// + /// Adds the given shift to the frequency of every breakpoint in the clip, including the + /// emphasis. + /// + /// + /// In other words, this property shifts all frequencies of the clip. The frequency shift is + /// added to each frequency value and needs to be between -1.0 and 1.0. If the resulting + /// frequency of a breakpoint is smaller than 0.0 or greater than 1.0, it is clipped to that + /// range. The frequency is clipped hard, no limiter is used. + /// + /// The clip needs to be loaded with Load() first. Loading a clip resets the shift back + /// to the default of 0.0. + /// + /// Setting the frequency shift has no effect on Android; it only works on iOS. + /// + /// A call to this property will change the frequency shift of a currently playing clip + /// right away. If no clip is playing, the shift is applied in the next call to + /// Play(). + [System.ComponentModel.DefaultValue(0.0f)] + public static float clipFrequencyShift + { + set + { + if (Init()) + { + LofeltHaptics.SetFrequencyShift(value); + } + } + } + + /// + /// Set the playback of a haptic clip to loop. + /// + /// + /// On Android, calling this will always put the playback position at the start of the clip. + /// Also, it will only have an effect when Play() is called again. + /// + /// On iOS, if a clip is already playing, calling this will leave the playback position as + /// it is and repeat when it reaches the end. No need to call Play() again for + /// changes to take effect. + /// + /// If the value is true, looping will be enabled which results + /// in repeating the playback until Stop() is called; if false, the haptic + /// clip will only be played once. + public static void Loop(bool enabled) + { + if (Init()) + { + LofeltHaptics.Loop(enabled); + } + isLoopingEnabledByUser = enabled; + } + + /// + /// Checks if the loaded haptic clip is playing. + /// + /// + /// Whether the loaded clip is playing + public static bool IsPlaying() + { + if (playbackFinishedTimer.Enabled) + { + return true; + } + else + { + return isPlaybackLooping; + } + } + + /// + /// Stops playback and resets the playback state. + /// + /// + /// Seek position, clip level, clip frequency shift and loop are reset to the + /// default values. + /// The currently loaded clip stays loaded. + /// \ref hapticsEnabled and \ref outputLevel are not reset. + public static void Reset() + { + if (clipLoaded) + { + Seek(0.0f); + Stop(); + clipLevel = 1.0f; + clipFrequencyShift = 0.0f; + Loop(false); + } + fallbackPreset = HapticPatterns.PresetType.None; + } + + /// + /// Processes an application focus change event. + /// + /// + /// If you have a HapticReceiver in your scene, the HapticReceiver + /// will take care of calling this method when needed. Otherwise it is your + /// responsibility to do so. + /// + /// When the application loses the focus, playback is stopped. + /// + /// Whether the application now has focus + public static void ProcessApplicationFocus(bool hasFocus) + { + if (!hasFocus) + { + // While LofeltHaptics stops playback when the app loses focus, + // calling Stop() here handles additional things such as invoking + // the PlaybackStopped Action. + Stop(); + } + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticController.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticController.cs.meta new file mode 100644 index 0000000..cd8f350 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eea19a9647af946678dbcea38129dd98 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticPatterns.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticPatterns.cs new file mode 100644 index 0000000..d900d38 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticPatterns.cs @@ -0,0 +1,514 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using System; +using UnityEngine; +using System.Globalization; + +namespace Lofelt.NiceVibrations +{ + /// + /// A collection of methods to play simple haptic patterns. + /// + /// + /// Each of the methods here load and play a simple haptic clip or a + /// haptic pattern, depending on the device capabilities. + /// + /// None of the methods here are thread-safe and should only be called from + /// the main (Unity) thread. Calling these methods from a secondary thread can + /// cause undefined behaviour and memory leaks. + /// + /// After playback has finished, the loaded clips in this class will remain + /// loaded in HapticController. + + public static class HapticPatterns + { + static String emphasisTemplate; + static String constantTemplate; + static NumberFormatInfo numberFormat; + static private float[] constantPatternTime = new float[] { 0.0f, 0.0f }; + + /// + /// Enum that represents all the types of haptic presets available + /// + public enum PresetType + { + Selection = 0, + Success = 1, + Warning = 2, + Failure = 3, + LightImpact = 4, + MediumImpact = 5, + HeavyImpact = 6, + RigidImpact = 7, + SoftImpact = 8, + None = -1 + } + + /// + /// Structure that represents a haptic pattern with amplitude variations. + /// + /// + /// \ref time values have be incremental to be compatible with Preset. + struct Pattern + { + public float[] time; + public float[] amplitude; + + static String clipJsonTemplate; + + static Pattern() + { + clipJsonTemplate = (Resources.Load("nv-pattern-template") as TextAsset).text; + } + + public Pattern(float[] time, float[] amplitude) + { + this.time = time; + this.amplitude = amplitude; + } + + // Converts a Pattern to a GamepadRumble + // + // Each pair of adjacent entries in the Pattern create one entry in the GamepadRumble. + public GamepadRumble ToRumble() + { + GamepadRumble result = new GamepadRumble(); + if (time.Length <= 1) + { + return result; + } + + Debug.Assert(time.Length == amplitude.Length); + + // The first pattern entry needs to have a time of 0.0 for the algorithm below to work + Debug.Assert(time[0] == 0.0f); + + int rumbleCount = time.Length - 1; + result.durationsMs = new int[rumbleCount]; + result.lowFrequencyMotorSpeeds = new float[rumbleCount]; + result.highFrequencyMotorSpeeds = new float[rumbleCount]; + result.totalDurationMs = 0; + for (int rumbleIndex = 0; rumbleIndex < rumbleCount; rumbleIndex++) + { + int patternDurationMs = (int)((time[rumbleIndex + 1] - time[rumbleIndex]) * 1000.0f); + result.durationsMs[rumbleIndex] = patternDurationMs; + result.lowFrequencyMotorSpeeds[rumbleIndex] = amplitude[rumbleIndex]; + result.highFrequencyMotorSpeeds[rumbleIndex] = amplitude[rumbleIndex]; + result.totalDurationMs += result.durationsMs[rumbleIndex]; + } + return result; + } + + // Converts a Pattern to a haptic clip JSON string. + public String ToClip() + { + if (clipJsonTemplate == null) + { + return ""; + } + + String amplitudeEnvelope = ""; + for (int i = 0; i < time.Length; i++) + { + float clampedAmplitude = Mathf.Clamp(amplitude[i], 0.0f, 1.0f); + amplitudeEnvelope += "{ \"time\":" + time[i].ToString(numberFormat) + "," + + "\"amplitude\":" + clampedAmplitude.ToString(numberFormat) + "}"; + + // Don't add a comma to the JSON data if we're at the end of the envelope + if (i + 1 < time.Length) + { + amplitudeEnvelope += ","; + } + } + + return clipJsonTemplate.Replace("{amplitude-envelope}", amplitudeEnvelope); + } + } + + // A haptic preset in its different representations + // + // A Preset has four different representations, as there are four different playback methods. + // Each representation is created at construction time, so that playing a + // Preset has no further conversion cost at playback time. + internal struct Preset + { + // For playback on iOS, using system haptics + public PresetType type; + + // For playback on Android devices without amplitude control + public float[] maximumAmplitudePattern; + + // For playback on Android devices with amplitude control + public byte[] jsonClip; + + // For playback on gamepads +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + public GamepadRumble gamepadRumble; +#endif + + public Preset(PresetType type, float[] time, float[] amplitude) + { + Debug.Assert(type != PresetType.None); + Pattern pattern = new Pattern(time, amplitude); + this.type = type; + this.maximumAmplitudePattern = pattern.time; +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + this.gamepadRumble = pattern.ToRumble(); +#endif + this.jsonClip = System.Text.Encoding.UTF8.GetBytes(pattern.ToClip()); + } + + public float GetDuration() + { + if (maximumAmplitudePattern.Length > 0) + { + return maximumAmplitudePattern[maximumAmplitudePattern.Length - 1]; + } + else + { + return 0f; + } + } + } + + /// + /// Predefined Preset that represents a "Selection" haptic preset + /// + internal static Preset Selection; + + /// + /// Predefined Preset that represents a "Light" haptic preset + /// + internal static Preset Light; + + /// + /// Predefined Preset that represents a "Medium" haptic preset + /// + internal static Preset Medium; + + /// + /// Predefined Preset that represents a "Heavy" haptic preset + /// + internal static Preset Heavy; + + /// + /// Predefined Preset that represents a "Rigid" haptic preset + /// + internal static Preset Rigid; + + /// + /// Predefined Preset that represents a "Soft" haptic preset + /// + internal static Preset Soft; + + /// + /// Predefined Preset that represents a "Success" haptic preset + /// + internal static Preset Success; + + /// + /// Predefined Preset that represents a "Failure" haptic preset + /// + internal static Preset Failure; + + /// + /// Predefined Preset that represents a "Warning" haptic preset + /// + internal static Preset Warning; + + static HapticPatterns() + { + emphasisTemplate = (Resources.Load("nv-emphasis-template") as TextAsset).text; + constantTemplate = (Resources.Load("nv-constant-template") as TextAsset).text; + + numberFormat = new NumberFormatInfo(); + numberFormat.NumberDecimalSeparator = "."; + + // Initialize presets after setting the number format, so that the correct decimal + // separator is used when building the JSON representation. + + Selection = new Preset(PresetType.Selection, new float[] { 0.0f, 0.04f }, + new float[] { 0.471f, 0.471f }); + + Light = new Preset(PresetType.LightImpact, new float[] { 0.000f, 0.040f }, + new float[] { 0.156f, 0.156f }); + + Medium = new Preset(PresetType.MediumImpact, new float[] { 0.000f, 0.080f }, + new float[] { 0.471f, 0.471f }); + + Heavy = new Preset(PresetType.HeavyImpact, new float[] { 0.0f, 0.16f }, + new float[] { 1.0f, 1.00f }); + + Rigid = new Preset(PresetType.RigidImpact, new float[] { 0.0f, 0.04f }, + new float[] { 1.0f, 1.00f }); + + Soft = new Preset(PresetType.SoftImpact, new float[] { 0.000f, 0.160f }, + new float[] { 0.156f, 0.156f }); + + Success = new Preset(PresetType.Success, new float[] { 0.0f, 0.040f, 0.080f, 0.240f }, + new float[] { 0.0f, 0.157f, 0.000f, 1.000f }); + + Failure = new Preset(PresetType.Failure, + new float[] { 0.0f, 0.080f, 0.120f, 0.200f, 0.240f, 0.400f, 0.440f, 0.480f }, + new float[] { 0.0f, 0.470f, 0.000f, 0.470f, 0.000f, 1.000f, 0.000f, 0.157f }); + + Warning = new Preset(PresetType.Warning, new float[] { 0.0f, 0.120f, 0.240f, 0.280f }, + new float[] { 0.0f, 1.000f, 0.000f, 0.470f }); + } + + /// + /// Plays a single emphasis point. + /// + /// + /// Plays a haptic clip that consists only of one breakpoint with emphasis. + /// On iOS, this translates to a transient, and on Android and gamepads to + /// a quick vibration. + /// + /// The amplitude of the emphasis, from 0.0 to 1.0 + /// The frequency of the emphasis, from 0.0 to 1.0 + public static void PlayEmphasis(float amplitude, float frequency) + { + if (emphasisTemplate == null || !HapticController.hapticsEnabled) + { + return; + } + + // Use HapticController.Play() to play a .haptic clip on mobile devices + // that support it, or to play a gamepad rumble if a gamepad is connected. + if (HapticController.Init() || GamepadRumbler.IsConnected()) + { + float clampedAmplitude = Mathf.Clamp(amplitude, 0.0f, 1.0f); + float clampedFrequency = Mathf.Clamp(frequency, 0.0f, 1.0f); + const float duration = 0.1f; + + String json = emphasisTemplate + .Replace("{amplitude}", clampedAmplitude.ToString(numberFormat)) + .Replace("{frequency}", clampedFrequency.ToString(numberFormat)) + .Replace("{duration}", duration.ToString(numberFormat)); + + // This preprocessor section will only run for non-mobile platforms + GamepadRumble rumble = new GamepadRumble(); +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + rumble.durationsMs = new int[] { (int)(duration * 1000) }; + rumble.lowFrequencyMotorSpeeds = new float[] { clampedAmplitude }; + rumble.highFrequencyMotorSpeeds = new float[] { clampedFrequency }; +#endif + + HapticController.Load(System.Text.Encoding.UTF8.GetBytes(json), rumble); + HapticController.Loop(false); + HapticController.Play(); + } + + // As a fallback, play a short buzz on Android, or a preset on iOS. + else if (DeviceCapabilities.isVersionSupported) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + LofeltHaptics.PlayMaximumAmplitudePattern(new float[]{ 0.0f, 0.05f }); +#elif (UNITY_IOS && !UNITY_EDITOR) + PresetType preset = presetTypeForEmphasis(amplitude); + LofeltHaptics.TriggerPresetHaptics((int)preset); +#endif + } + } + + /// + /// Automatically selects the fallback preset based on the emphasis point amplitude. + /// + /// + /// The amplitude of the emphasis, from 0.0 to 1.0 + static PresetType presetTypeForEmphasis(float amplitude) + { + if (amplitude > 0.5f) + { + return HapticPatterns.PresetType.HeavyImpact; + } + else if (amplitude <= 0.5f && amplitude > 0.3) + { + return HapticPatterns.PresetType.MediumImpact; + } + else + { + return HapticPatterns.PresetType.LightImpact; + } + } + + /// + /// Plays a haptic with constant amplitude and frequency. + /// + /// + /// On iOS and with gamepads, you can use HapticController::clipLevel to modulate the haptic + /// while it is playing. iOS additional supports modulating the frequency with + /// HapticController::clipFrequencyShift. + /// + /// When \ref DeviceCapabilities.meetsAdvancedRequirements returns false on mobile, + /// the behavior of this method is different for iOS and Android: + ///
    + ///
  • On iOS, it will play the preset HapticPatterns.PresetType.HeavyImpact.
  • + /// + ///
  • On Android, it will play a pattern with maximum amplitude for the set duration + /// since there is no amplitude control.
  • + /// + ///
+ /// Amplitude, from 0.0 to 1.0 + /// Frequency, from 0.0 to 1.0 + /// Play duration in seconds + public static void PlayConstant(float amplitude, float frequency, float duration) + { + if (constantTemplate == null || !HapticController.hapticsEnabled) + { + return; + } + + float clampedAmplitude = Mathf.Clamp(amplitude, 0.0f, 1.0f); + float clampedFrequency = Mathf.Clamp(frequency, 0.0f, 1.0f); + float clampedDurationSecs = Mathf.Max(duration, 0.0f); + + String json = constantTemplate + .Replace("{duration}", clampedDurationSecs.ToString(numberFormat)); + + // This preprocessor section will only run for non-mobile platforms + GamepadRumble rumble = new GamepadRumble(); +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + int rumbleDurationMs = (int)(clampedDurationSecs * 1000); + const int rumbleEntryDurationMs = 16; // One rumble entry per frame at 60 FPS, which is the limit of what GamepadRumbler can play + int rumbleEntryCount = rumbleDurationMs / rumbleEntryDurationMs; + rumble.durationsMs = new int[rumbleEntryCount]; + rumble.lowFrequencyMotorSpeeds = new float[rumbleEntryCount]; + rumble.highFrequencyMotorSpeeds = new float[rumbleEntryCount]; + + // Create many rumble entries instead of just one. With just one entry, changing + // clipLevel while the rumble is playing would have no effect, as GamepadRumbler applies + // a change only to the next rumble entry, not the one currently playing. + for (int i = 0; i < rumbleEntryCount; i++) + { + rumble.durationsMs[i] = rumbleEntryDurationMs; + rumble.lowFrequencyMotorSpeeds[i] = 1.0f; + rumble.highFrequencyMotorSpeeds[i] = 1.0f; + } +#endif + + if (HapticController.Init() || GamepadRumbler.IsConnected()) + { + HapticController.Load(System.Text.Encoding.UTF8.GetBytes(json), rumble); + HapticController.Loop(false); + HapticController.clipLevel = clampedAmplitude; + HapticController.clipFrequencyShift = clampedFrequency; + HapticController.Play(); + } + else if (DeviceCapabilities.isVersionSupported) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + constantPatternTime[1] = duration; + LofeltHaptics.PlayMaximumAmplitudePattern(constantPatternTime); +#elif (UNITY_IOS && !UNITY_EDITOR) + HapticPatterns.PlayPreset(PresetType.HeavyImpact); +#endif + } + } + + static Preset GetPresetForType(PresetType type) + { + Debug.Assert(type != PresetType.None); + + switch (type) + { + case PresetType.Selection: + return Selection; + case PresetType.LightImpact: + return Light; + case PresetType.MediumImpact: + return Medium; + case PresetType.HeavyImpact: + return Heavy; + case PresetType.RigidImpact: + return Rigid; + case PresetType.SoftImpact: + return Soft; + case PresetType.Success: + return Success; + case PresetType.Failure: + return Failure; + case PresetType.Warning: + return Warning; + } + + // Silence compiler warning about not all code paths returning something + return Medium; + } + + /// + /// Plays a set of predefined haptic patterns. + /// + /// + /// These predefined haptic patterns are played and represented in different ways for iOS, + /// Android and gamepads. + /// + /// - On iOS, this function triggers system haptics that are native to iOS. Calling + /// \ref HapticController.Stop() won't stop haptics. + /// - On Android devices that can play .haptic clips (DeviceCapabilities.meetsAdvancedRequirements + /// is true) and on gamepads, this function plays a haptic pattern that has a similar + /// experience to the matching iOS system haptics. + /// - On Android devices that can not play .haptic clips (DeviceCapabilities.meetsAdvancedRequirements + /// is false), this function plays a haptic pattern that has a similar experience to + /// the matching iOS system haptics, by turning the motor off and on at maximum amplitude. + /// + /// This is a "fire-and-forget" method. Other functionalities like seeking, looping, and + /// runtime modulation won't work after calling this method. + /// + /// Type of preset represented by a \ref PresetType enum + public static void PlayPreset(PresetType presetType) + { + if (!HapticController.hapticsEnabled || presetType == PresetType.None) + { + return; + } + + Preset preset = GetPresetForType(presetType); + +#if (UNITY_IOS && !UNITY_EDITOR) + LofeltHaptics.TriggerPresetHaptics((int)presetType); + return; +#else + if (HapticController.Init() || GamepadRumbler.IsConnected()) + { +#if ((!UNITY_ANDROID && !UNITY_IOS) || UNITY_EDITOR) && NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED && ENABLE_INPUT_SYSTEM && !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + HapticController.Load(preset.jsonClip, preset.gamepadRumble); +#else + HapticController.Load(preset.jsonClip); +#endif + HapticController.Loop(false); + HapticController.Play(); + return; + } + + if (DeviceCapabilities.isVersionSupported) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + LofeltHaptics.PlayMaximumAmplitudePattern(preset.maximumAmplitudePattern); + return; +#endif + } +#endif + } + + /// + /// Returns the haptic preset duration. + /// + /// + /// While a preset is played back in different ways on iOS, Android and gamepads, the + /// duration is similar for each playback method. + /// + /// Type of preset represented by a \ref PresetType enum + /// Returns a float with a the preset duration; if the selected preset is `None`, it returns 0 + public static float GetPresetDuration(PresetType presetType) + { + if (presetType == PresetType.None) + { + return 0; + } + + return GetPresetForType(presetType).GetDuration(); + } + } + +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticPatterns.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticPatterns.cs.meta new file mode 100644 index 0000000..a11d0e6 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticPatterns.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e98a6cfb8386a479a8a5c3ded1f05862 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticReceiver.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticReceiver.cs new file mode 100644 index 0000000..e96ade1 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticReceiver.cs @@ -0,0 +1,108 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using UnityEngine; + +namespace Lofelt.NiceVibrations +{ + /// + /// A MonoBehaviour that forwards global properties from HapticController and + /// handles events + /// + /// + /// While HapticSource provides a per-clip MonoBehaviour API for the functionality + /// in HapticController, HapticReceiver provides a MonoBehaviour API for + /// the global functionality in HapticController. + /// + /// HapticReceiver is also responsible for global event handling, such as an application + /// focus change. To make this work correctly, your scene should have exactly one + /// HapticReceiver component, similar to how a scene should have exactly one + /// AudioListener. + /// + /// In the future HapticReceiver might receive parameters and distance to + /// HapticSource components, and can be used for global parameter control through Unity + /// Editor GUI. + [AddComponentMenu("Nice Vibrations/Haptic Receiver")] + public class HapticReceiver : MonoBehaviour, ISerializationCallbackReceiver + { + // These two fields are only used for serialization and deserialization. + // HapticController manages the output haptic level and global haptic toggle, + // HapticReceiver forwards these properties so they are available in a + // MonoBehaviour. + // To be able to serialize these properties, HapticReceiver needs to have + // fields for them. Before serialization, these fields are set to the values + // from HapticController, and after deserialization the values are restored + // back to HapticController. + [SerializeField] + [Range(0.0f, 5.0f)] + private float _outputLevel = 1.0f; + [SerializeField] + private bool _hapticsEnabled = true; + + /// + /// Loads all fields from HapticController. + /// + public void OnBeforeSerialize() + { + _outputLevel = HapticController._outputLevel; + _hapticsEnabled = HapticController._hapticsEnabled; + } + + /// + /// Writes all fields to HapticController. + /// + public void OnAfterDeserialize() + { + HapticController._outputLevel = _outputLevel; + HapticController._hapticsEnabled = _hapticsEnabled; + } + + /// + /// Forwarded HapticController::outputLevel + /// + [System.ComponentModel.DefaultValue(1.0f)] + public float outputLevel + { + get { return HapticController.outputLevel; } + set { HapticController.outputLevel = value; } + } + + + /// + /// Forwarded HapticController::hapticsEnabled + /// + [System.ComponentModel.DefaultValue(true)] + public bool hapticsEnabled + { + get { return HapticController.hapticsEnabled; } + set { HapticController.hapticsEnabled = value; } + } + + /// + /// Initializes HapticController. + /// + /// + /// This ensures that the initialization time is spent at startup instead of when + /// the first haptic is triggered during gameplay. + void Start() + { + HapticController.Init(); + } + + /// + /// Forwards an application focus change event to HapticController. + /// + void OnApplicationFocus(bool hasFocus) + { + HapticController.ProcessApplicationFocus(hasFocus); + } + + /// + /// Stops haptic playback on the gamepad when destroyed, to make sure the gamepad + /// stops vibrating when quitting the application. + /// + void OnDestroy() + { + GamepadRumbler.Stop(); + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticReceiver.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticReceiver.cs.meta new file mode 100644 index 0000000..8ba2383 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticReceiver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ceb29a83998eb4949bc0a9c8e5662fa1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 24c63d27288824cf68c83ec01e0f3643, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticSource.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticSource.cs new file mode 100644 index 0000000..ec118d9 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticSource.cs @@ -0,0 +1,262 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using UnityEngine; + +namespace Lofelt.NiceVibrations +{ + /// + /// Provides haptic playback functionality for a single haptic clip. + /// + /// + /// HapticSource plays back the HapticClip assigned in the \ref clip property + /// when calling Play(). It also provides various ways to control playback, such as + /// seeking, looping and amplitude/frequency modulation. + /// + /// When a gamepad is connected, the haptic clip will be played back on that gamepad. + /// See the HapticController documentation for more details about gamepad support. + /// + /// At the moment, playback of a haptic source is not triggered automatically + /// by e.g. proximity between the HapticReceiver and the HapticSource, + /// so you need to call Play() to trigger playback. + /// + /// You can place multiple HapticSource components in your scene, with a different + /// HapticClip assigned to each. + /// + /// HapticSource provides a per-clip MonoBehaviour API for the functionality + /// in HapticController, while HapticReceiver provides a MonoBehaviour API + /// for the global functionality in HapticController. + /// + /// HapticSourceInspector provides a custom editor for HapticSource for the + /// Inspector. + [AddComponentMenu("Nice Vibrations/Haptic Source")] + public class HapticSource : MonoBehaviour + { + const int DEFAULT_PRIORITY = 128; + + /// The HapticClip this HapticSource loads and plays. + public HapticClip clip; + + /// + /// The priority of the HapticSource + /// + /// + /// This property is set by HapticSourceInspector. 0 is the highest priority and 256 + /// is the lowest priority. + /// + /// The default value is 128. + public int priority = DEFAULT_PRIORITY; + + /// + /// Jump in time position of haptic source playback. + /// + /// + /// Initially set to 0.0 seconds. + /// This value can only be set when using Seek(). + float seekTime = 0.0f; + + [SerializeField] + HapticPatterns.PresetType _fallbackPreset = HapticPatterns.PresetType.None; + + /// + /// The haptic preset to be played when it's not possible to play a haptic clip + /// + [System.ComponentModel.DefaultValue(HapticPatterns.PresetType.None)] + public HapticPatterns.PresetType fallbackPreset + { + get { return _fallbackPreset; } + set { _fallbackPreset = value; } + } + + [SerializeField] + bool _loop = false; + + /// + /// Set the haptic source to loop playback of the haptic clip. + /// + /// + /// It will only have any effect once Play() is called. + /// + /// See HapticController::Loop() for further details. + [System.ComponentModel.DefaultValue(false)] + public bool loop + { + get { return _loop; } + set { _loop = value; } + } + + [SerializeField] + float _level = 1.0f; + + /// + /// The level of the haptic source + /// + /// + /// Haptic source level is applied in combination with output level (which can be set on either + /// HapticReceiver or HapticController according to preference), to the currently playing + /// haptic clip. The combination of these two levels and the amplitude within the loaded + /// haptic at a given moment in time determines the strength of the vibration felt on the device. See + /// HapticController::clipLevel for further details. + [System.ComponentModel.DefaultValue(1.0)] + public float level + { + get { return _level; } + set + { + _level = value; + + if (IsLoaded()) + { + HapticController.clipLevel = _level; + } + } + } + + [SerializeField] + float _frequencyShift = 0.0f; + + /// + /// This shift is added to the frequency of every breakpoint in the clip, including the + /// emphasis. + /// + /// + /// See HapticController::clipFrequencyShift for further details. + [System.ComponentModel.DefaultValue(0.0)] + public float frequencyShift + { + get { return _frequencyShift; } + set + { + _frequencyShift = value; + + if (IsLoaded()) + { + HapticController.clipFrequencyShift = _frequencyShift; + } + } + } + + /// The HapticSource that is currently loaded into HapticController. + /// This can be null if nothing was ever loaded, or if HapticController::Load() + /// was called directly, bypassing HapticSource. + static HapticSource loadedHapticSource = null; + + /// The HapticSource that was last played. + /// This can be null if nothing was ever player, or if HapticController::Play() + /// was called directly, bypassing HapticSource. + /// The lastPlayedHapticSource isn't necessarily playing now, lastPlayedHapticSource + /// will remain set even if playback has finished or was stopped. + static HapticSource lastPlayedHapticSource = null; + + static HapticSource() + { + // When HapticController::Load() or HapticController::Play() is + // called directly, bypassing HapticSource, reset loadedHapticSource + // and lastPlayedHapticSource. + HapticController.LoadedClipChanged += () => + { + loadedHapticSource = null; + }; + HapticController.PlaybackStarted += () => + { + lastPlayedHapticSource = null; + }; + } + + /// + /// Loads and plays back the haptic clip. + /// + /// + /// At the moment only one haptic clip at a time can be played. If another + /// HapticSource is currently playing and has lower priority, its playback will + /// be stopped. + /// + /// If a seek time within the time range of the clip has been set with Seek(), + /// it will jump to that position if \ref loop is false. If \ref loop + /// is true, seeking will have no effect. + /// + /// It will loop playback in case \ref loop is true. + public void Play() + { + if (CanPlay()) + { + // + // Load + // + HapticController.Load(clip); + loadedHapticSource = this; + + // + // Apply properties like loop, modulation and seek position + // + HapticController.Loop(loop); + + HapticController.clipLevel = level; + HapticController.clipFrequencyShift = frequencyShift; + + if (seekTime != 0.0f && !loop) + { + HapticController.Seek(seekTime); + } + + // + // Play + // + HapticController.fallbackPreset = fallbackPreset; + HapticController.Play(); + lastPlayedHapticSource = this; + } + } + + private bool CanPlay() + { + return (!HapticController.IsPlaying() || + (lastPlayedHapticSource != null && priority <= lastPlayedHapticSource.priority)); + } + + /// + /// Checks if the current HapticSource has been loaded into HapticController. + /// + /// + /// This is used to avoid triggering operations on HapticController while + /// another HapticSource is loaded. + private bool IsLoaded() + { + return Object.ReferenceEquals(this, loadedHapticSource); + } + + /// + /// Stops playback that was previously started with Play(). + /// + public void Stop() + { + if (IsLoaded()) + { + HapticController.Stop(); + } + } + + /// + /// Sets the time position to jump to when Play() is called. + /// + /// + /// It will only have an effect once Play() is called. + /// + /// The position in the clip, in seconds + public void Seek(float time) + { + this.seekTime = time; + } + + /// + /// When a GameObject is disabled, stop playback if this HapticSource is + /// playing. + /// + public void OnDisable() + { + if (HapticController.IsPlaying() && IsLoaded()) + { + this.Stop(); + } + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticSource.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticSource.cs.meta new file mode 100644 index 0000000..cdb65dc --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/HapticSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d20df93fb7de8457baa15a213a53ab19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7c1be57d46a3143daa1fe62dbc59772f, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons.meta new file mode 100644 index 0000000..0947622 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 729f668a205524058a62426043ee3083 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticReceiverIcon.png b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticReceiverIcon.png new file mode 100644 index 0000000..f088ee6 Binary files /dev/null and b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticReceiverIcon.png differ diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticReceiverIcon.png.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticReceiverIcon.png.meta new file mode 100644 index 0000000..43b7cc9 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticReceiverIcon.png.meta @@ -0,0 +1,92 @@ +fileFormatVersion: 2 +guid: 24c63d27288824cf68c83ec01e0f3643 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticSourceIcon.png b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticSourceIcon.png new file mode 100644 index 0000000..22683a9 Binary files /dev/null and b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticSourceIcon.png differ diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticSourceIcon.png.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticSourceIcon.png.meta new file mode 100644 index 0000000..7e56ba0 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Icons/HapticSourceIcon.png.meta @@ -0,0 +1,92 @@ +fileFormatVersion: 2 +guid: 7c1be57d46a3143daa1fe62dbc59772f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/JNIHelpers.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/JNIHelpers.cs new file mode 100644 index 0000000..8bc7124 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/JNIHelpers.cs @@ -0,0 +1,135 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#if (UNITY_ANDROID && !UNITY_EDITOR) + +using System; +using UnityEngine; + +namespace Lofelt.NiceVibrations +{ + // Android JNI call wrappers that are more efficient than AndroidJavaObject::Call() + // + // Calling a method via AndroidJavaObject, e.g. `lofeltHaptics.Call("play")`, is inefficient: + // - It looks up the method by name for each call + // - It allocates memory during method lookup and argument conversion + // + // JNIHelpers provides alternative Call() methods that are more efficient: + // - It allows calling by method ID rather by method name, so that the method only needs to + // be looked up once, not for every call + // - It does not allocate memory for converting the arguments to jvalue[] + // + // In addition to that, exceptions thrown in Java are handled automatically by logging them. + // + // The Call() overload here do not cover all cases that AndroidJavaObject::Call() covers. For + // example, only methods with one argument are supported, and that only for certain types. In + // addition, not all overloads are free of allocations. This however is good enough so that the + // calls triggered by common playback scenarios such as HapticController::Play() and + // HapticPatterns::PlayPreset() don't allocate. + internal static class JNIHelpers + { + // The array for the JNI arguments is created here, so that it doesn't need to be created + // for every call. This saves the allocation in each call. + // The array supports only methods with 0 or 1 argument, but that covers our needs. + static jvalue[] jniArgs = new jvalue[1]; + + // Returns an exception message and stack trace for the given Java exception + static String javaThrowableToString(IntPtr throwable) + { + IntPtr throwableClass = AndroidJNI.FindClass("java/lang/Throwable"); + IntPtr androidUtilLogClass = AndroidJNI.FindClass("android/util/Log"); + try + { + IntPtr toStringMethodId = AndroidJNI.GetMethodID(throwableClass, "toString", "()Ljava/lang/String;"); + IntPtr getStackTraceStringMethodId = AndroidJNI.GetStaticMethodID(androidUtilLogClass, "getStackTraceString", "(Ljava/lang/Throwable;)Ljava/lang/String;"); + string exceptionMessage = AndroidJNI.CallStringMethod(throwable, toStringMethodId, new jvalue[] { }); + jniArgs[0].l = throwable; + string exceptionCallStack = AndroidJNI.CallStaticStringMethod(androidUtilLogClass, getStackTraceStringMethodId, jniArgs); + return exceptionMessage + "\n" + exceptionCallStack; + } + finally + { + if (throwable != IntPtr.Zero) + AndroidJNI.DeleteLocalRef(throwable); + if (throwableClass != IntPtr.Zero) + AndroidJNI.DeleteLocalRef(throwableClass); + if (androidUtilLogClass != IntPtr.Zero) + AndroidJNI.DeleteLocalRef(androidUtilLogClass); + } + } + + public static void Call(AndroidJavaObject obj, IntPtr methodId, jvalue[] jniArgs) + { + if (methodId == IntPtr.Zero) + { + return; + } + + try + { + AndroidJNI.CallVoidMethod(obj.GetRawObject(), methodId, jniArgs); + IntPtr throwable = AndroidJNI.ExceptionOccurred(); + if (throwable != IntPtr.Zero) + { + AndroidJNI.ExceptionClear(); + String exception = javaThrowableToString(throwable); + Debug.LogError(exception); + } + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + public static void Call(AndroidJavaObject obj, IntPtr methodId) + { + jniArgs[0].l = System.IntPtr.Zero; + Call(obj, methodId, jniArgs); + } + + public static void Call(AndroidJavaObject obj, IntPtr methodId, float arg) + { + jniArgs[0].f = arg; + Call(obj, methodId, jniArgs); + } + + public static void Call(AndroidJavaObject obj, IntPtr methodId, bool arg) + { + jniArgs[0].z = arg; + Call(obj, methodId, jniArgs); + } + + public static void Call(AndroidJavaObject obj, IntPtr methodId, float[] arg) + { + // The allocations in the next two lines could probably be removed to optimize this + // further. + object[] args = new object[] { arg }; + jvalue[] jniArgs = AndroidJNIHelper.CreateJNIArgArray(args); + try + { + JNIHelpers.Call(obj, methodId, jniArgs); + } + finally + { + AndroidJNIHelper.DeleteJNIArgArray(args, jniArgs); + } + } + + // The method isn't yet optimized to reduce allocations, but unlike the other overloads of + // Call(), it supports non-void return types. + public static ReturnType Call(AndroidJavaObject obj, string methodName) + { + try + { + return obj.Call(methodName); + } + catch (Exception ex) + { + Debug.LogException(ex); + return default(ReturnType); + } + } + + } +} +#endif \ No newline at end of file diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/JNIHelpers.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/JNIHelpers.cs.meta new file mode 100644 index 0000000..9926d84 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/JNIHelpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 309cd98b547c14b48b9f1c523a6fdc26 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/LofeltHaptics.cs b/Assets/Scripts/Lofelt/NiceVibrations/Components/LofeltHaptics.cs new file mode 100644 index 0000000..404e62c --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/LofeltHaptics.cs @@ -0,0 +1,295 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using UnityEngine; +using System; + +#if (UNITY_ANDROID && !UNITY_EDITOR) +using System.Text; +using System.Runtime.InteropServices; +#elif (UNITY_IOS && !UNITY_EDITOR) +using UnityEngine.iOS; +using System.Runtime.InteropServices; +#endif + +namespace Lofelt.NiceVibrations +{ + /// + /// C# wrapper for the Lofelt Studio Android and iOS SDK. + /// + /// + /// You should not use this class directly, use HapticController instead, or the + /// MonoBehaviour classes HapticReceiver and HapticSource. + /// + /// The Lofelt Studio Android and iOS SDK are included in Nice Vibrations as pre-compiled + /// binary plugins. + /// + /// Each method here delegates to either the Android or iOS SDK. The methods should only be + /// called if DeviceMeetsMinimumPlatformRequirements() returns true, otherwise there will + /// be runtime errors. + /// + /// All the methods do nothing when running in the Unity editor. + /// + /// Before calling any other method, Initialize() needs to be called. + /// + /// Errors are printed and swallowed, no exceptions are thrown. On iOS, this happens inside + /// the SDK, on Android this happens with try/catch blocks in this class and in JNIHelpers. + public static class LofeltHaptics + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + static AndroidJavaObject lofeltHaptics; + static AndroidJavaObject hapticPatterns; + static long nativeController; + + // Cache the most commonly used JNI method IDs during initialization. + // Calling a Java method via its method ID is faster and uses less allocations than + // calling a method by string, like e.g. 'lofeltHaptics.Call("play")'. + static IntPtr playMethodId = IntPtr.Zero; + static IntPtr stopMethodId = IntPtr.Zero; + static IntPtr seekMethodId = IntPtr.Zero; + static IntPtr loopMethodId = IntPtr.Zero; + static IntPtr setAmplitudeMultiplicationMethodId = IntPtr.Zero; + static IntPtr playMaximumAmplitudePattern = IntPtr.Zero; + + [DllImport("lofelt_sdk")] + private static extern bool lofeltHapticsLoadDirect(IntPtr controller, [In] byte[] bytes, long size); + +#elif (UNITY_IOS && !UNITY_EDITOR) + // imports of iOS Framework bindings + + [DllImport("__Internal")] + private static extern bool lofeltHapticsDeviceMeetsMinimumRequirementsBinding(); + + [DllImport("__Internal")] + private static extern IntPtr lofeltHapticsInitBinding(); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsLoadBinding(IntPtr controller, [In] byte[] bytes, long size); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsPlayBinding(IntPtr controller); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsStopBinding(IntPtr controller); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsSeekBinding(IntPtr controller, float time); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsSetAmplitudeMultiplicationBinding(IntPtr controller, float factor); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsSetFrequencyShiftBinding(IntPtr controller, float shift); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsLoopBinding(IntPtr controller, bool enable); + + [DllImport("__Internal")] + private static extern float lofeltHapticsGetClipDurationBinding(IntPtr controller); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsReleaseBinding(IntPtr controller); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsSystemHapticsTriggerBinding(int type); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsSystemHapticsInitializeBinding(); + + [DllImport("__Internal")] + private static extern bool lofeltHapticsSystemHapticsReleaseBinding(); + + static IntPtr controller = IntPtr.Zero; + + static bool systemHapticsInitialized = false; +#endif + + /// + /// Initializes the iOS framework or Android library plugin. + /// + /// + /// This needs to be called before calling any other method. + public static void Initialize() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + try + { + using (var unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) + using (var context = unityPlayerClass.GetStatic("currentActivity")) + { + lofeltHaptics = new AndroidJavaObject("com.lofelt.haptics.LofeltHaptics", context); + nativeController = lofeltHaptics.Call("getControllerHandle"); + hapticPatterns = new AndroidJavaObject("com.lofelt.haptics.HapticPatterns", context); + + playMethodId = AndroidJNIHelper.GetMethodID(lofeltHaptics.GetRawClass(), "play", "()V", false); + stopMethodId = AndroidJNIHelper.GetMethodID(lofeltHaptics.GetRawClass(), "stop", "()V", false); + seekMethodId = AndroidJNIHelper.GetMethodID(lofeltHaptics.GetRawClass(), "seek", "(F)V", false); + loopMethodId = AndroidJNIHelper.GetMethodID(lofeltHaptics.GetRawClass(), "loop", "(Z)V", false); + setAmplitudeMultiplicationMethodId = AndroidJNIHelper.GetMethodID(lofeltHaptics.GetRawClass(), "setAmplitudeMultiplication", "(F)V", false); + playMaximumAmplitudePattern = AndroidJNIHelper.GetMethodID(hapticPatterns.GetRawClass(), "playMaximumAmplitudePattern", "([F)V", false); + } + } + catch (Exception ex) + { + Debug.LogException(ex); + } +#elif (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsSystemHapticsInitializeBinding(); + systemHapticsInitialized = true; + controller = lofeltHapticsInitBinding(); +#endif + } + + /// + /// Releases the resources used by the iOS framework or Android library plugin. + /// + public static void Release() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + try + { + lofeltHaptics.Dispose(); + lofeltHaptics = null; + + hapticPatterns.Dispose(); + hapticPatterns = null; + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } +#elif (UNITY_IOS && !UNITY_EDITOR) + if(DeviceCapabilities.isVersionSupported) { + lofeltHapticsSystemHapticsReleaseBinding(); + if(controller != IntPtr.Zero) { + lofeltHapticsReleaseBinding(controller); + controller = IntPtr.Zero; + } + } +#endif + } + + public static bool DeviceMeetsMinimumPlatformRequirements() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + return JNIHelpers.Call(lofeltHaptics, "deviceMeetsMinimumRequirements"); +#elif (UNITY_IOS && !UNITY_EDITOR) + return lofeltHapticsDeviceMeetsMinimumRequirementsBinding(); +#else + return true; +#endif + } + + public static void Load(byte[] data) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + // For performance reasons, we do *not* call into the Java API with + // `lofeltHaptics.Call("load", data)` here. Instead, we bypass the Java layer and + // call into the native library directly, saving the costly conversion from + // C#'s byte[] to Java's byte[]. + // + // No exception handling needed here, lofeltHapticsLoadDirect() is a native method that + // doesn't throw an exception and instead logs the error. + lofeltHapticsLoadDirect((IntPtr)nativeController, data, data.Length); +#elif (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsLoadBinding(controller, data, data.Length); +#endif + } + + public static float GetClipDuration() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + return JNIHelpers.Call(lofeltHaptics, "getClipDuration"); +#elif (UNITY_IOS && !UNITY_EDITOR) + return lofeltHapticsGetClipDurationBinding(controller); +#else + //No haptic clip was loaded with Lofelt SDK, so it returns 0.0f + return 0.0f; +#endif + } + + public static void Play() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + JNIHelpers.Call(lofeltHaptics, playMethodId); +#elif (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsPlayBinding(controller); +#endif + } + + public static void PlayMaximumAmplitudePattern(float[] timings) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + JNIHelpers.Call(hapticPatterns, playMaximumAmplitudePattern, timings); +#endif + } + + public static void Stop() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + JNIHelpers.Call(lofeltHaptics, stopMethodId); +#elif (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsStopBinding(controller); +#endif + } + + public static void StopPattern() + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + try + { + hapticPatterns.Call("stopPattern"); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } +#endif + } + + public static void Seek(float time) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + JNIHelpers.Call(lofeltHaptics, seekMethodId, time); +#elif (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsSeekBinding(controller, time); +#endif + } + + public static void SetAmplitudeMultiplication(float factor) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + JNIHelpers.Call(lofeltHaptics, setAmplitudeMultiplicationMethodId, factor); +#elif (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsSetAmplitudeMultiplicationBinding(controller, factor); +#endif + } + + public static void SetFrequencyShift(float shift) + { +#if (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsSetFrequencyShiftBinding(controller, shift); +#endif + } + + public static void Loop(bool enabled) + { +#if (UNITY_ANDROID && !UNITY_EDITOR) + JNIHelpers.Call(lofeltHaptics, loopMethodId, enabled); +#elif (UNITY_IOS && !UNITY_EDITOR) + lofeltHapticsLoopBinding(controller, enabled); +#endif + } + + public static void TriggerPresetHaptics(int type) + { +#if (UNITY_IOS && !UNITY_EDITOR) + if (!systemHapticsInitialized) + { + lofeltHapticsSystemHapticsInitializeBinding(); + systemHapticsInitialized = true; + } + lofeltHapticsSystemHapticsTriggerBinding(type); +#endif + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/LofeltHaptics.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/LofeltHaptics.cs.meta new file mode 100644 index 0000000..411bcc5 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/LofeltHaptics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 921537c8cf6464a24bd55f54ec8ea0d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources.meta new file mode 100644 index 0000000..657a720 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dfbca06fe23ec4830a998e7db8247870 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-constant-template.txt b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-constant-template.txt new file mode 100644 index 0000000..8b96dc6 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-constant-template.txt @@ -0,0 +1,33 @@ +{ + "version": { + "major": 1, + "minor": 0, + "patch": 0 + }, + "signals": { + "continuous": { + "envelopes": { + "amplitude": [ + { + "time": 0.0, + "amplitude": 1.0 + }, + { + "time": {duration}, + "amplitude": 1.0 + } + ], + "frequency": [ + { + "time": 0, + "frequency": 0.0 + }, + { + "time": {duration}, + "frequency": 0.0 + } + ] + } + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-constant-template.txt.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-constant-template.txt.meta new file mode 100644 index 0000000..e87f520 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-constant-template.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e4781704d93144109a483e1899b7cec6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-emphasis-template.txt b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-emphasis-template.txt new file mode 100644 index 0000000..ae3b902 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-emphasis-template.txt @@ -0,0 +1,37 @@ +{ + "version": { + "major": 1, + "minor": 0, + "patch": 0 + }, + "signals": { + "continuous": { + "envelopes": { + "amplitude": [ + { + "time": 0.0, + "amplitude": 0.0, + "emphasis": { + "amplitude": {amplitude}, + "frequency": {frequency} + } + }, + { + "time": {duration}, + "amplitude": 0.0 + } + ], + "frequency": [ + { + "time": 0, + "frequency": 1.0 + }, + { + "time": {duration}, + "frequency": 1.0 + } + ] + } + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-emphasis-template.txt.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-emphasis-template.txt.meta new file mode 100644 index 0000000..dd5bc85 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-emphasis-template.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e1c679e9069854e06b54bb65f38215ff +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-pattern-template.txt b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-pattern-template.txt new file mode 100644 index 0000000..79ac208 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-pattern-template.txt @@ -0,0 +1,14 @@ +{ + "version": { + "major": 1, + "minor": 0, + "patch": 0 + }, + "signals": { + "continuous": { + "envelopes": { + "amplitude": [ {amplitude-envelope} ] + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-pattern-template.txt.meta b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-pattern-template.txt.meta new file mode 100644 index 0000000..db6e73c --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Components/Resources/nv-pattern-template.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cbb8181953d2a49a49f926ebcc75626c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Editor.meta b/Assets/Scripts/Lofelt/NiceVibrations/Editor.meta new file mode 100644 index 0000000..3633b33 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 290aee7a75d474f7985eaad9d87ac572 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticImporter.cs b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticImporter.cs new file mode 100644 index 0000000..85534b4 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticImporter.cs @@ -0,0 +1,119 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using System.IO; +using System.Runtime.InteropServices; +using System; +using UnityEngine; +using System.Text; + +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; +#elif UNITY_2019_4_OR_NEWER +using UnityEditor.Experimental.AssetImporters; +#endif + +namespace Lofelt.NiceVibrations +{ + /// + /// Provides an importer for the HapticClip component. + /// + /// + /// The importer takes a .haptic file and converts it into a HapticClip. + [ScriptedImporter(version: 3, ext: "haptic", AllowCaching = true)] + public class HapticImporter : ScriptedImporter + { +#if !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + [DllImport("nice_vibrations_editor_plugin")] + private static extern IntPtr nv_plugin_convert_haptic_to_gamepad_rumble([In] byte[] bytes, long size); + + [DllImport("nice_vibrations_editor_plugin")] + private static extern void nv_plugin_destroy(IntPtr gamepadRumble); + + [DllImport("nice_vibrations_editor_plugin")] + private static extern UIntPtr nv_plugin_get_length(IntPtr gamepadRumble); + + [DllImport("nice_vibrations_editor_plugin")] + private static extern void nv_plugin_get_durations(IntPtr gamepadRumble, [Out] int[] durations); + + [DllImport("nice_vibrations_editor_plugin")] + private static extern void nv_plugin_get_low_frequency_motor_speeds(IntPtr gamepadRumble, [Out] float[] lowFrequencies); + + [DllImport("nice_vibrations_editor_plugin")] + private static extern void nv_plugin_get_high_frequency_motor_speeds(IntPtr gamepadRumble, [Out] float[] highFrequencies); + + // We can not use "[return: MarshalAs(UnmanagedType.LPUTF8Str)]" here, and have to use + // IntPtr for the return type instead. Otherwise, the C# runtime tries to free the returned + // string, which is invalid as the native plugin keeps ownership of the string. + // We use PtrToStringUTF8() to manually convert the IntPtr to a string instead. + [DllImport("nice_vibrations_editor_plugin")] + private static extern IntPtr nv_plugin_get_last_error(); + + [DllImport("nice_vibrations_editor_plugin")] + private static extern UIntPtr nv_plugin_get_last_error_length(); + + // Alternative to Marshal.PtrToStringUTF8() which was introduced in .NET 5 and isn't yet + // supported by Unity + private string PtrToStringUTF8(IntPtr ptr, int length) + { + byte[] bytes = new byte[length]; + Marshal.Copy(ptr, bytes, 0, length); + return Encoding.UTF8.GetString(bytes, 0, length); + } +#endif + + public override void OnImportAsset(AssetImportContext ctx) + { + // Load .haptic clip from file + var fileName = Path.GetFileNameWithoutExtension(ctx.assetPath); + var jsonBytes = File.ReadAllBytes(ctx.assetPath); + var hapticClip = HapticClip.CreateInstance(); + hapticClip.json = jsonBytes; + +#if !NICE_VIBRATIONS_DISABLE_GAMEPAD_SUPPORT + // Convert JSON to a GamepadRumble struct. The conversion algorithm is inside the native + // library nice_vibrations_editor_plugin. That plugin is only used in the Unity editor, and + // not at runtime. + GamepadRumble rumble = default; + IntPtr nativeRumble = nv_plugin_convert_haptic_to_gamepad_rumble(jsonBytes, jsonBytes.Length); + if (nativeRumble != IntPtr.Zero) + { + try + { + uint length = (uint)nv_plugin_get_length(nativeRumble); + rumble.durationsMs = new int[length]; + rumble.lowFrequencyMotorSpeeds = new float[length]; + rumble.highFrequencyMotorSpeeds = new float[length]; + + nv_plugin_get_durations(nativeRumble, rumble.durationsMs); + nv_plugin_get_low_frequency_motor_speeds(nativeRumble, rumble.lowFrequencyMotorSpeeds); + nv_plugin_get_high_frequency_motor_speeds(nativeRumble, rumble.highFrequencyMotorSpeeds); + + int totalDurationMs = 0; + foreach (int duration in rumble.durationsMs) + { + totalDurationMs += duration; + } + rumble.totalDurationMs = totalDurationMs; + } + finally + { + nv_plugin_destroy(nativeRumble); + } + } + else + { + var lastErrorPtr = nv_plugin_get_last_error(); + var lastErrorLength = (int)nv_plugin_get_last_error_length(); + var lastError = PtrToStringUTF8(lastErrorPtr, lastErrorLength); + Debug.LogWarning($"Failed to convert haptic clip {ctx.assetPath} to gamepad rumble: {lastError}"); + } + + hapticClip.gamepadRumble = rumble; +#endif + + // Use hapticClip as the imported asset + ctx.AddObjectToAsset("com.lofelt.HapticClip", hapticClip); + ctx.SetMainObject(hapticClip); + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticImporter.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticImporter.cs.meta new file mode 100644 index 0000000..e96189f --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc84fb4fa9e67485a972c887d976d004 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticSourceInspector.cs b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticSourceInspector.cs new file mode 100644 index 0000000..342face --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticSourceInspector.cs @@ -0,0 +1,155 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using System.IO; + +namespace Lofelt.NiceVibrations +{ + [CustomEditor(typeof(HapticSource))] + [CanEditMultipleObjects] + /// + /// Provides an inspector for the HapticSource component + /// + /// + /// The inspector lets you link a HapticSource to a HapticClip. + public class HapticSourceInspector : Editor + { + string hapticsDirectory; + + SerializedProperty hapticClip; + SerializedProperty priority; + SerializedProperty level; + SerializedProperty frequencyShift; + SerializedProperty loop; + SerializedProperty fallbackPreset; + + public static GUIContent hapticClipLabel = EditorGUIUtility.TrTextContent("Haptic Clip", "The HapticClip asset played by the HapticSource."); + public static GUIContent fallbackPresetLabel = EditorGUIUtility.TrTextContent("Haptic Preset fallback", "Set the haptic preset to play in case the device doesn't support playback of haptic clips"); + public static GUIContent loopLabel = EditorGUIUtility.TrTextContent("Loop", "Set the haptic source to loop playback of the haptic clip"); + + void OnEnable() + { + hapticClip = serializedObject.FindProperty("clip"); + priority = serializedObject.FindProperty("priority"); + level = serializedObject.FindProperty("_level"); + frequencyShift = serializedObject.FindProperty("_frequencyShift"); + fallbackPreset = serializedObject.FindProperty("_fallbackPreset"); + loop = serializedObject.FindProperty("_loop"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(hapticClip, hapticClipLabel); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(fallbackPreset, fallbackPresetLabel); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(loop, loopLabel); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + CreatePrioritySlider(); + CreateLevelSlider(); + CreateFrequencyShiftSlider(); + + serializedObject.ApplyModifiedProperties(); + } + + /// Helper function to create a priority slider for haptic source with High and Max text labels. + void CreatePrioritySlider() + { + Rect position = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + + EditorGUI.IntSlider(position, priority, 0, 256); + + // Move to next line + position.y += EditorGUIUtility.singleLineHeight; + + // Subtract the label + position.x += EditorGUIUtility.labelWidth; + position.width -= EditorGUIUtility.labelWidth; + + // Subtract the text field width thats drawn with slider + position.width -= EditorGUIUtility.fieldWidth; + + GUIStyle style = GUI.skin.label; + TextAnchor defaultAlignment = GUI.skin.label.alignment; + style.alignment = TextAnchor.UpperLeft; EditorGUI.LabelField(position, "High", style); + style.alignment = TextAnchor.UpperRight; EditorGUI.LabelField(position, "Low", style); + GUI.skin.label.alignment = defaultAlignment; + + // Allow space for the High/Low labels + EditorGUILayout.Space(); + EditorGUILayout.Space(); + EditorGUILayout.Space(); + } + + /// Helper function to create a level slider for haptic + /// source with labels. + void CreateLevelSlider() + { + Rect position = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + + EditorGUI.Slider(position, level, 0.0f, 5.0f); + + // Move to next line + position.y += EditorGUIUtility.singleLineHeight; + + // Subtract the label + position.x += EditorGUIUtility.labelWidth; + position.width -= EditorGUIUtility.labelWidth; + + // Subtract the text field width thats drawn with slider + position.width -= EditorGUIUtility.fieldWidth; + + GUIStyle style = GUI.skin.label; + TextAnchor defaultAlignment = GUI.skin.label.alignment; + style.alignment = TextAnchor.UpperLeft; EditorGUI.LabelField(position, "0.0", style); + style.alignment = TextAnchor.UpperRight; EditorGUI.LabelField(position, "5.0", style); + GUI.skin.label.alignment = defaultAlignment; + + // Allow space for the labels + EditorGUILayout.Space(); + EditorGUILayout.Space(); + EditorGUILayout.Space(); + } + + /// Helper function to create a frequency shift slider for haptic + /// source with labels. + void CreateFrequencyShiftSlider() + { + Rect position = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + + EditorGUI.Slider(position, frequencyShift, -1.0f, 1.0f); + + // Move to next line + position.y += EditorGUIUtility.singleLineHeight; + + // Subtract the label + position.x += EditorGUIUtility.labelWidth; + position.width -= EditorGUIUtility.labelWidth; + + // Subtract the text field width thats drawn with slider + position.width -= EditorGUIUtility.fieldWidth; + + GUIStyle style = GUI.skin.label; + TextAnchor defaultAlignment = GUI.skin.label.alignment; + style.alignment = TextAnchor.UpperLeft; EditorGUI.LabelField(position, "-1.0", style); + style.alignment = TextAnchor.UpperRight; EditorGUI.LabelField(position, "1.0", style); + GUI.skin.label.alignment = defaultAlignment; + + // Allow space for the labels + EditorGUILayout.Space(); + EditorGUILayout.Space(); + EditorGUILayout.Space(); + } + } +} diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticSourceInspector.cs.meta b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticSourceInspector.cs.meta new file mode 100644 index 0000000..4b89d54 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Editor/HapticSourceInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90a030b5ab0574cd9880e136f5e0261c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Editor/Lofelt.NiceVibrations.Editor.asmdef b/Assets/Scripts/Lofelt/NiceVibrations/Editor/Lofelt.NiceVibrations.Editor.asmdef new file mode 100644 index 0000000..01980f9 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Editor/Lofelt.NiceVibrations.Editor.asmdef @@ -0,0 +1,18 @@ +{ + "name": "Lofelt.NiceVibrations.Editor", + "rootNamespace": "", + "references": [ + "GUID:7399982fb54df4bb981f9e015a651afa" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Editor/Lofelt.NiceVibrations.Editor.asmdef.meta b/Assets/Scripts/Lofelt/NiceVibrations/Editor/Lofelt.NiceVibrations.Editor.asmdef.meta new file mode 100644 index 0000000..eb588a4 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Editor/Lofelt.NiceVibrations.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 67bc5fafbf62b48858241ce814d3d489 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Lofelt.NiceVibrations.asmdef b/Assets/Scripts/Lofelt/NiceVibrations/Lofelt.NiceVibrations.asmdef new file mode 100644 index 0000000..2ba2225 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Lofelt.NiceVibrations.asmdef @@ -0,0 +1,21 @@ +{ + "name": "Lofelt.NiceVibrations", + "references": [ + "GUID:75469ad4d38634e559750d17036d5f7c" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.inputsystem", + "expression": "1.0", + "define": "NICE_VIBRATIONS_INPUTSYSTEM_INSTALLED" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Scripts/Lofelt/NiceVibrations/Lofelt.NiceVibrations.asmdef.meta b/Assets/Scripts/Lofelt/NiceVibrations/Lofelt.NiceVibrations.asmdef.meta new file mode 100644 index 0000000..ca1cec9 --- /dev/null +++ b/Assets/Scripts/Lofelt/NiceVibrations/Lofelt.NiceVibrations.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7399982fb54df4bb981f9e015a651afa +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/Audio/Generated/AudioEnumIds.cs b/Assets/Scripts/OCES/Audio/Generated/AudioEnumIds.cs index 199092b..decab45 100644 --- a/Assets/Scripts/OCES/Audio/Generated/AudioEnumIds.cs +++ b/Assets/Scripts/OCES/Audio/Generated/AudioEnumIds.cs @@ -9,9 +9,12 @@ namespace OCES.Audio { public const uint GameState = 1; + public const uint TileMaterial = 2; + public static void RegisterAllGameState() { StateGroupRegistry.Register(1); + StateGroupRegistry.Register(2); } } } diff --git a/Assets/Scripts/OCES/Audio/Generated/AudioEnums.cs b/Assets/Scripts/OCES/Audio/Generated/AudioEnums.cs index 04d5468..60dc6e3 100644 --- a/Assets/Scripts/OCES/Audio/Generated/AudioEnums.cs +++ b/Assets/Scripts/OCES/Audio/Generated/AudioEnums.cs @@ -15,4 +15,11 @@ namespace OCES.Audio Bass = 6, // 测试用值 } + public enum TileMaterial + { + Normal, // 普通牌 + Ice, // 冰 + Cloud, // 云 + } + } diff --git a/Assets/Scripts/OCES/Audio/Generated/AudioObject.cs b/Assets/Scripts/OCES/Audio/Generated/AudioObject.cs index 3f33ccf..dcc6696 100644 --- a/Assets/Scripts/OCES/Audio/Generated/AudioObject.cs +++ b/Assets/Scripts/OCES/Audio/Generated/AudioObject.cs @@ -98,6 +98,7 @@ public partial class AudioObject : IBinarySerializable /// 0 = 随机播放 /// 1 = 顺序播放 /// 2 = 混合播放 + /// 3 = 切换播放 /// public ContainerType ContainerType { get; set; } @@ -130,6 +131,33 @@ public partial class AudioObject : IBinarySerializable /// public bool RandomType { get; set; } + /// + /// Volume Step阈值 ms + /// + public uint VolumeStepThreshold { get; set; } + + /// + /// 起始音量 + /// dB + /// + public int Volume { get; set; } + + /// + /// 音量变化幅度 + /// dB + /// + public int VolumeStep { get; set; } + + /// + /// 要绑定的 StateGroup ID + /// + public uint SwitchGroupId { get; set; } + + /// + /// 匹配失败时的备用 AudioObject ID + /// + public uint DefaultSwitchId { get; set; } + public void DeSerialize(BinaryReader reader) { @@ -166,6 +194,11 @@ public partial class AudioObject : IBinarySerializable BlendCrossFadeType = (BlendCrossFadeType)reader.ReadByte(); LimitRepetition = reader.ReadByte(); RandomType = reader.ReadBoolean(); + VolumeStepThreshold = reader.ReadUInt32(); + Volume = reader.ReadInt32(); + VolumeStep = reader.ReadInt32(); + SwitchGroupId = reader.ReadUInt32(); + DefaultSwitchId = reader.ReadUInt32(); } public void Serialize(BinaryWriter writer) @@ -202,6 +235,11 @@ public partial class AudioObject : IBinarySerializable writer.Write((byte)BlendCrossFadeType); writer.Write(LimitRepetition); writer.Write(RandomType); + writer.Write(VolumeStepThreshold); + writer.Write(Volume); + writer.Write(VolumeStep); + writer.Write(SwitchGroupId); + writer.Write(DefaultSwitchId); } } diff --git a/Assets/Scripts/OCES/Audio/Generated/AudioObjectDefinitions.cs b/Assets/Scripts/OCES/Audio/Generated/AudioObjectDefinitions.cs index 1940cba..712ba12 100644 --- a/Assets/Scripts/OCES/Audio/Generated/AudioObjectDefinitions.cs +++ b/Assets/Scripts/OCES/Audio/Generated/AudioObjectDefinitions.cs @@ -69,53 +69,40 @@ public static class AudioObjectDefinitions { "Bar", 52 }, { "Beat", 53 }, { "Grid", 54 }, - { "sfx_amb_desert", 2000 }, - { "sfx_amb_forest", 2001 }, - { "sfx_anim_common_item_fly", 3000 }, - { "sfx_anim_corePlay_character_footstep_grass", 3001 }, - { "sfx_anim_corePlay_character_footstep_sand", 3002 }, - { "sfx_anim_corePlay_character_footstep_stone", 3003 }, - { "sfx_anim_corePlay_fireBall", 3004 }, - { "sfx_anim_corePlay_freeze", 3005 }, - { "sfx_anim_corePlay_getIn_devil", 3006 }, - { "sfx_anim_corePlay_getIn_dragon", 3007 }, - { "sfx_anim_corePlay_getIn_ghost", 3008 }, - { "sfx_anim_corePlay_newBoxFromStorage", 3009 }, - { "sfx_anim_corePlay_shield_broke_wood", 3010 }, - { "sfx_anim_corePlay_shield_broke_crystal", 3011 }, - { "sfx_anim_corePlay_shield_broke_eggRoll", 3012 }, - { "sfx_anim_corePlay_shield_show_crystal", 3013 }, - { "sfx_anim_corePlay_shield_show_eggRoll", 3014 }, - { "sfx_anim_corePlay_shield_show_wood", 3015 }, - { "sfx_anim_corePlay_shield_underAttack_wood", 3016 }, - { "sfx_anim_corePlay_shield_underAttack_crystal", 3017 }, - { "sfx_anim_corePlay_shield_underAttack_eggRoll", 3018 }, - { "sfx_anim_corePlay_slow", 3019 }, - { "sfx_anim_corePlay_speedUp", 3020 }, - { "sfx_anim_corePlay_useProp_", 3021 }, - { "sfx_anim_cutScene_in", 3022 }, - { "sfx_anim_cutScene_out", 3023 }, - { "sfx_notice_common_negative", 4000 }, - { "sfx_notice_corePlay_losing", 4001 }, - { "sfx_notice_corePlay_restart", 4002 }, - { "sfx_notice_corePlay_warning", 4003 }, - { "sfx_notice_guide", 4004 }, - { "sfx_notice_spinWheel_click", 4005 }, - { "sfx_notice_spinWheel_getReward", 4006 }, - { "sfx_notice_corePlay_levelStart_hard", 4007 }, - { "sfx_ui_labelSwitch_home", 5000 }, - { "sfx_ui_panel_common_close", 5001 }, - { "sfx_ui_panel_common_open", 5002 }, - { "sfx_ui_panel_continue_open", 5003 }, - { "sfx_ui_panel_corePlay_guide_open", 5004 }, - { "sfx_ui_panel_initPack_open", 5005 }, - { "sfx_ui_panel_piggyBank_close", 5006 }, - { "sfx_ui_panel_piggyBank_open", 5007 }, - { "sfx_ui_panel_removeAds_open", 5008 }, - { "0", 5009 }, - { "sfx_ui_panel_summerPack_open", 5010 }, - { "sfx_ui_panel_unlockItem_open", 5011 }, - { "voice_princess_fear", 9000 }, + { "NVDice", 55 }, + { "NVHeartbeats", 56 }, + { "au_sfx_notice_level_countDown_edge", 57 }, + { "au_sfx_notice_level_countDown_time", 58 }, + { "0,62", 59 }, + { "1,65", 59 }, + { "2,68", 59 }, + { "0,63", 60 }, + { "1,66", 60 }, + { "2,69", 60 }, + { "0,64", 61 }, + { "1,67", 61 }, + { "2,70", 61 }, + { "au_coreplay_choose_v120_a", 62 }, + { "au_coreplay_unchoose_v120_a", 63 }, + { "au_coreplay_clear_v120_a", 64 }, + { "au_sfx_ui_button_corePlay_choose_ice1", 65 }, + { "au_sfx_ui_button_corePlay_choose_ice2", 65 }, + { "au_sfx_ui_button_corePlay_choose_ice3", 65 }, + { "au_sfx_ui_button_corePlay_unchoose_ice1", 66 }, + { "au_sfx_ui_button_corePlay_unchoose_ice2", 66 }, + { "au_sfx_ui_button_corePlay_unchoose_ice3", 66 }, + { "au_sfx_ui_button_corePlay_clear_ice1", 67 }, + { "au_sfx_ui_button_corePlay_clear_ice2", 67 }, + { "au_sfx_ui_button_corePlay_clear_ice3", 67 }, + { "au_sfx_ui_button_corePlay_choose_cloud1", 68 }, + { "au_sfx_ui_button_corePlay_choose_cloud2", 68 }, + { "au_sfx_ui_button_corePlay_choose_cloud3", 68 }, + { "au_sfx_ui_button_corePlay_unchoose_cloud1", 69 }, + { "au_sfx_ui_button_corePlay_unchoose_cloud2", 69 }, + { "au_sfx_ui_button_corePlay_unchoose_cloud3", 69 }, + { "au_sfx_ui_button_corePlay_clear_cloud1", 70 }, + { "au_sfx_ui_button_corePlay_clear_cloud2", 70 }, + { "au_sfx_ui_button_corePlay_clear_cloud3", 70 }, }; public static readonly HashSet AmbiguousNames = new() @@ -143,6 +130,33 @@ public static class AudioObjectDefinitions "Chinese Number 08", "Chinese Number 09", "Chinese Number 10", + "0,62", + "1,65", + "2,68", + "0,63", + "1,66", + "2,69", + "0,64", + "1,67", + "2,70", + "au_sfx_ui_button_corePlay_choose_ice1", + "au_sfx_ui_button_corePlay_choose_ice2", + "au_sfx_ui_button_corePlay_choose_ice3", + "au_sfx_ui_button_corePlay_unchoose_ice1", + "au_sfx_ui_button_corePlay_unchoose_ice2", + "au_sfx_ui_button_corePlay_unchoose_ice3", + "au_sfx_ui_button_corePlay_clear_ice1", + "au_sfx_ui_button_corePlay_clear_ice2", + "au_sfx_ui_button_corePlay_clear_ice3", + "au_sfx_ui_button_corePlay_choose_cloud1", + "au_sfx_ui_button_corePlay_choose_cloud2", + "au_sfx_ui_button_corePlay_choose_cloud3", + "au_sfx_ui_button_corePlay_unchoose_cloud1", + "au_sfx_ui_button_corePlay_unchoose_cloud2", + "au_sfx_ui_button_corePlay_unchoose_cloud3", + "au_sfx_ui_button_corePlay_clear_cloud1", + "au_sfx_ui_button_corePlay_clear_cloud2", + "au_sfx_ui_button_corePlay_clear_cloud3", }; } } diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AudioObject.cs b/Assets/Scripts/OCES/Audio/HandWritten/AudioObject.cs new file mode 100644 index 0000000..2133f92 --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/AudioObject.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace OCES.Audio +{ + public partial class AudioObjectConfig + { + Dictionary> m_switchMapping; + + internal void PreParseSwitchMappings() + { + this.m_switchMapping = new Dictionary>(); + foreach (AudioObject audioObject in AudioObjectList()) + { + if (audioObject.ContainerType != ContainerType.Switch) continue; + this.m_switchMapping[audioObject.Id] = ParseSwitchMapping(audioObject); + } + } + + public AudioObject GetMappingResult(uint switchContainerId, Enum enumState) + { + if (!this.m_switchMapping.TryGetValue(switchContainerId, out Dictionary switchMapping)) + return null; + + return switchMapping.TryGetValue(enumState.GetHashCode(), out uint audioObjectId) ? QueryById(audioObjectId) : null; + + } + + Dictionary ParseSwitchMapping(AudioObject switchContainer) + { + Dictionary switchMapping = new(); + foreach (string name in switchContainer.Name) + { + string[] parts = name.Split(','); + if(parts.Length != 2) + { + Debug.LogWarning($"[AudioSystem] 无法解析 Switch Container {switchContainer.Id} 的映射关系!请检查表"); + continue; + } + + if (!int.TryParse(parts[0].Trim(), out int stateValue)) + { + Debug.LogWarning($"[AudioSystem] 无法解析 映射关系!请查表"); + continue; + } + + if (!uint.TryParse(parts[1].Trim(), out uint childId)) + { + Debug.LogWarning(""); + continue; + } + + switchMapping.Add(stateValue, childId); + } + return switchMapping; + } + + internal AudioObject GetDefaultSwitchOrFallback(AudioObject switchContainer) + { + if (switchContainer.DefaultSwitchId == 0) + return null; + AudioObject defaultChildAudioObject = QueryById(switchContainer.DefaultSwitchId); + if (defaultChildAudioObject != null) + return defaultChildAudioObject; + + Debug.LogWarning($"[AudioSystem] DefaultSwitch AudioObject {switchContainer.DefaultSwitchId} 不存在。"); + return null; + } + } +} diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AudioObject.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/AudioObject.cs.meta new file mode 100644 index 0000000..9de33f9 --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/AudioObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 68c35969f92d4bb0ba3239d852115c53 +timeCreated: 1776244015 \ No newline at end of file diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AudioSystem.cs b/Assets/Scripts/OCES/Audio/HandWritten/AudioSystem.cs index e29430c..536ebae 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/AudioSystem.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/AudioSystem.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; +using System.IO; using UnityEngine; using UnityEngine.Audio; using DG.Tweening; @@ -10,7 +10,9 @@ namespace OCES.Audio public class AudioSystem : MonoBehaviour { public static AudioSystem Instance { get; private set; } - + // ReSharper disable once MemberCanBePrivate.Global + public IReadOnlyDictionary ActiveStates { get; private set; } + const string k_audioConfigPath = "AudioData"; const string k_audioResourcePath = "Audios"; @@ -21,7 +23,7 @@ namespace OCES.Audio AudioGroupConfig m_groups; AudioMixer m_mixer; Tween m_lowpassTween; - + // ───────────────────────────────────────────── // 公开接口 // ───────────────────────────────────────────── @@ -42,6 +44,16 @@ namespace OCES.Audio public void Play(AudioObject audioObject, Action onPlay = null) { + if (audioObject.ContainerType == ContainerType.Switch) + { + audioObject = ResolveSwitchContainer(audioObject); + if (audioObject == null) + { + Debug.Log("[AudioSystem] 无法解析Switch Container,检查配置表!"); + return; + } + } + this.m_sfxSystem.TryPlay(audioObject, onPlay); } @@ -49,8 +61,7 @@ namespace OCES.Audio { Play((uint)audioId); } - - + [Obsolete("Use Play(uint) instead")] public void Play(string audioName) { @@ -114,6 +125,7 @@ namespace OCES.Audio public void SetState(TEnum state) where TEnum : Enum { this.m_musicSystem.OnStateChanged(state); + ActiveStates = this.m_musicSystem.ActiveStates; } // ───────────────────────────────────────────── @@ -139,6 +151,7 @@ namespace OCES.Audio AudioSourcePool sfxPool = new(sfxPoolRoot.transform); // 不传 mixer group,让 SfxSystem 自己设置 this.m_sfxSystem = gameObject.AddComponent(); this.m_audioObjects = AudioConfigLoader.Load($"{k_audioConfigPath}/AudioObject"); + this.m_audioObjects.PreParseSwitchMappings(); this.m_groups = AudioConfigLoader.Load($"{k_audioConfigPath}/AudioGroup"); this.m_sfxSystem.Initialize(this.m_groups, this.m_mixer, sfxPool); // 传入 pool @@ -182,19 +195,67 @@ namespace OCES.Audio // ── 注册 StateGroup ── EnumIds.RegisterAllGameState(); + ActiveStates = new Dictionary(); + // ── 启动默认音乐与环境音 ── // 触发一次初始状态,让音乐系统从默认状态开始匹配 - SetState(GameState.Home); + //SetState(GameState.Home); } + + AudioObject ResolveSwitchContainer(AudioObject switchContainer) + { + // 遍历 ActiveStates 找到 TypeId 匹配的枚举类型 + Enum currentStateValue = null; + bool foundGroup = false; + foreach (KeyValuePair keyValuePair in ActiveStates) + { + if (StateGroupRegistry.GetTypeId(keyValuePair.Key) != switchContainer.SwitchGroupId) continue; + currentStateValue = keyValuePair.Value; + foundGroup = true; + break; + } + + if (!foundGroup) + { + Debug.LogWarning($"[AudioSystem] Switch Container {switchContainer.Id} 找不到 TypeId={switchContainer.SwitchGroupId} 对应的状态组。"); + return this.m_audioObjects.GetDefaultSwitchOrFallback(switchContainer); + } + + // 解析AudioObject对象 + AudioObject childContainer = this.m_audioObjects.GetMappingResult(switchContainer.Id, currentStateValue); + return childContainer ?? this.m_audioObjects.GetDefaultSwitchOrFallback(switchContainer); + } + + } - static class AudioConfigLoader + public static class AudioConfigLoader { - public static Dictionary Load(string path, Func keySelector) + public static T Load(string configPath, string fileName) + where T : IBinarySerializable, new() { - string json = System.IO.File.ReadAllText(path); - var wrapper = JsonUtility.FromJson>(json); - return wrapper.AudioObjects.ToDictionary(keySelector); + string path = Path.Combine( + Application.dataPath, "Resources", configPath, fileName); + + if (!File.Exists(path)) + { + Debug.LogError($"[AudioImportTool] 找不到配置文件: {path}"); + return default; + } + + try + { + T config = new T(); + using MemoryStream ms = new(File.ReadAllBytes(path)); + using BinaryReader reader = new(ms); + config.DeSerialize(reader); + return config; + } + catch (Exception e) + { + Debug.LogError($"[AudioImportTool] 配置表反序列化失败 {fileName}: {e.Message}"); + return default; + } } public static T Load(string tableName) where T : IBinarySerializable, new() diff --git a/Assets/Scripts/OCES/Audio/HandWritten/DebugInfoCollector.cs b/Assets/Scripts/OCES/Audio/HandWritten/DebugInfoCollector.cs index fdc162a..64b7328 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/DebugInfoCollector.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/DebugInfoCollector.cs @@ -6,7 +6,7 @@ using UnityEngine.UI; namespace OCES.Audio.Editor { -#if UNITY_EDITOR +#if UNITY_EDITOR || DEVELOPMENT_BUILD public sealed class DebugInfoCollector : MonoBehaviour { @@ -14,7 +14,7 @@ namespace OCES.Audio.Editor public Dictionary ClipConcurrentCount = new(); public List ActiveSounds = new(); - public Dictionary ActiveStates = new(); + public Dictionary ActiveStates = new(); readonly StringBuilder m_stringBuilder = new(); Text m_textComponent; @@ -35,10 +35,9 @@ namespace OCES.Audio.Editor this.m_stringBuilder.Clear(); this.m_stringBuilder.AppendLine("Current States:"); - foreach (KeyValuePair activeState in this.ActiveStates) + foreach (KeyValuePair activeState in this.ActiveStates) { - string enumName = Enum.GetName(activeState.Key, activeState.Value) ?? activeState.Value.ToString(); - this.m_stringBuilder.AppendLine($"{activeState.Key.Name} is {enumName}"); + this.m_stringBuilder.AppendLine($"{activeState.Key.Name} is {activeState.Value}"); } this.m_stringBuilder.AppendLine(); diff --git a/Assets/Scripts/OCES/Audio/HandWritten/Editor.meta b/Assets/Scripts/OCES/Audio/HandWritten/Editor.meta new file mode 100644 index 0000000..5a8a478 --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74dabdb41aa034e7b958b53e70d9ae0d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/Audio/HandWritten/Editor/AudioImportTool.cs b/Assets/Scripts/OCES/Audio/HandWritten/Editor/AudioImportTool.cs new file mode 100644 index 0000000..20a6b2a --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/Editor/AudioImportTool.cs @@ -0,0 +1,198 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace OCES.Audio +{ + + public static class AudioImportTool + { + const string k_audioResourcePath = "Audios"; + const string k_audioConfigPath = "AudioData"; + + static string AudioAbsolutePath + { + get { return Path.Combine(Application.dataPath, "Resources", k_audioResourcePath); } + } + static string ConfigAbsolutePath + { + get { return Path.Combine(Application.dataPath, "Resources", k_audioConfigPath); } + } + + [MenuItem("Tools/Audio/Apply Audio Import Settings")] + public static void RunFromMenu() + { + if (EditorUtility.DisplayDialog( + "Apply Audio Import Settings", + $"将对 {AudioAbsolutePath} 下所有文件重新应用导入设置,确认继续?", + "确认", "取消")) + { + Run(); + } + } + + /// + /// Executes the audio import tool from the command line in batch mode. + /// This method is designed to be called via Unity's -executeMethod command line argument + /// and serves as the entry point for automated audio import workflows. + /// It initializes the process and delegates to the main Run method to apply + /// audio import settings to all supported audio files in the configured directory. + /// + public static void RunCli() + { + Debug.Log("[AudioImportTool] CLI 模式启动"); + Run(); + } + + public static void Run() + { + // 1. 加载配置表 + var audioObjectConfig = AudioConfigLoader.Load(ConfigAbsolutePath, "AudioObject.bytes"); + var musicSegmentConfig = AudioConfigLoader.Load(ConfigAbsolutePath, "MusicSegment.bytes"); + if (audioObjectConfig == null || musicSegmentConfig == null) + { + Debug.LogError("[AudioImportTool] 配置表加载失败,终止"); + return; + } + + // 2. 扫描文件 + List supportedExtensions = new() { ".wav", ".ogg" }; + DirectoryInfo dir = new(AudioAbsolutePath); + FileInfo[] files = dir.GetFiles().Where(f => supportedExtensions.Contains(f.Extension.ToLower())).ToArray(); + int total = files.Length, processed = 0, failed = 0; + + AssetDatabase.StartAssetEditing(); // 批量操作,暂停自动刷新 + try + { + foreach (FileInfo file in files) + { + // 转成 Assets/... 相对路径供 AssetDatabase 使用 + string assetPath = "Assets" + file.FullName + .Replace(Application.dataPath, "") + .Replace("\\", "/"); + + EditorUtility.DisplayProgressBar( + "Audio Import Tool", + $"处理: {file.Name} ({processed}/{total})", + (float)processed / total); + + bool ok = ProcessFile(assetPath, file.Name, audioObjectConfig, musicSegmentConfig); + if (ok) processed++; + else failed++; + } + } + finally + { + EditorUtility.ClearProgressBar(); + AssetDatabase.StopAssetEditing(); + AssetDatabase.SaveAssets(); + } + + Debug.Log($"[AudioImportTool] 完成:{processed} 成功,{failed} 失败,共 {total} 个文件"); + } + + static bool ProcessFile( + string assetPath, string fileName, + AudioObjectConfig audioObjectConfig, MusicSegmentConfig musicSegmentConfig) + { + AudioImporter importer = AssetImporter.GetAtPath(assetPath) as AudioImporter; + if (!importer) + { + Debug.LogWarning($"[AudioImportTool] 无法获取 AudioImporter: {assetPath}"); + return false; + } + + AudioClip clip = AssetDatabase.LoadAssetAtPath(assetPath); + if (!clip) + { + Debug.LogWarning($"[AudioImportTool] 无法加载 AudioClip: {assetPath}"); + return false; + } + + float duration = clip.length; + string fileNameNoExt = Path.GetFileNameWithoutExtension(fileName); + AudioCategory category = ClassifyAudio(fileNameNoExt, audioObjectConfig, musicSegmentConfig, out AudioObject audioObject); + + importer.ClearSampleSettingOverride("Android"); + importer.ClearSampleSettingOverride("iOS"); + + AudioImporterSampleSettings settings = importer.defaultSampleSettings; + settings.compressionFormat = AudioCompressionFormat.Vorbis; + + settings.sampleRateSetting = AudioSampleRateSetting.OverrideSampleRate; + settings.preloadAudioData = audioObject?.Haptic != 0; + switch (category) + { + case AudioCategory.Music: + settings.sampleRateOverride = 44100; + settings.quality = 0.13f; + settings.loadType = duration switch + { + <= 5 => AudioClipLoadType.DecompressOnLoad, + >= 15 => AudioClipLoadType.Streaming, + _ => AudioClipLoadType.CompressedInMemory, + }; + break; + case AudioCategory.Voice: + case AudioCategory.SFX: + default: + settings.sampleRateOverride = 22050; // 音效2022.3.62f3没有32kHz这一档,要是有的话这一档其实最合适 + settings.quality = 0.5f; + settings.loadType = duration switch + { + >= 15 => AudioClipLoadType.Streaming, + _ => AudioClipLoadType.DecompressOnLoad, + }; + break; + } + + importer.defaultSampleSettings = settings; + importer.forceToMono = false; + importer.SaveAndReimport(); + return true; + } + + enum AudioCategory { Music, SFX, Voice } + + static AudioCategory ClassifyAudio( + string fileName, // 不含扩展名 + AudioObjectConfig audioObjectConfig, + MusicSegmentConfig musicSegmentConfig, + out AudioObject matchedObject) + { + matchedObject = null; + + // 1. MusicSegment 表命中 → Music + MusicSegment segment = musicSegmentConfig.MusicSegmentList() + .FirstOrDefault(musicSegment => musicSegment.Name == fileName); + if (segment != null) + return AudioCategory.Music; + + // 2. AudioObject 表命中 → 按 MixingType + AudioObject audioObject = audioObjectConfig.AudioObjectList() + .FirstOrDefault(audioObject => audioObject.Name != null && audioObject.Name.Contains(fileName)); + if (audioObject != null) + { + matchedObject = audioObject; + return audioObject.MixingType == MixingType.Voice + ? AudioCategory.Voice + : AudioCategory.SFX; // SFX + Accent 都走 SFX 分支 + } + + // 3. 文件名 fallback + string lower = fileName.ToLowerInvariant(); + if (lower.Contains("music") || lower.Contains("bgm")) + return AudioCategory.Music; + if (lower.Contains("sfx")) + return AudioCategory.SFX; + if (lower.Contains("voice")) + return AudioCategory.Voice; + + // 4. 完全兜底 + Debug.LogWarning($"[AudioImportTool] 无法分类: {fileName},默认当作 SFX 处理"); + return AudioCategory.SFX; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OCES/Audio/HandWritten/Editor/AudioImportTool.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/Editor/AudioImportTool.cs.meta new file mode 100644 index 0000000..08d1d8e --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/Editor/AudioImportTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 114d56912b8874446b70f4c83af327b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs b/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs index 8d13bc8..e361d5a 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs @@ -29,6 +29,7 @@ namespace OCES.Audio Random = 0, Sequence, Blend, + Switch, } public enum BlendCrossFadeType @@ -84,19 +85,10 @@ namespace OCES.Audio public partial class MusicPath : IPathEntry { } public partial class AmbiencePath : IPathEntry { } - - public partial class MusicContainerConfig + + public class SwitchEntry { - /// - /// 解析拍号字符串(如 "4/4", "3/4"),返回每小节拍数。 - /// - public static int GetBeatsPerBar(string timeSig) - { - if (string.IsNullOrEmpty(timeSig)) return 4; - string[] parts = timeSig.Split('/'); - if (parts.Length >= 1 && int.TryParse(parts[0], out int beats)) - return beats; - return 4; - } + public uint SwitchValue; + public uint AudioObjectId; } } diff --git a/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs index 84f773f..7abb7ac 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs @@ -9,8 +9,10 @@ namespace OCES.Audio /// public class MusicStateRouter { - // key: StateGroup enum Type,value: 当前激活的 enum 整数值 - readonly Dictionary m_activeStates = new(); + + // key: StateGroup enum Type,value: 当前激活的 enum 值 + readonly Dictionary m_activeStates = new(); + readonly MusicPathConfig m_musicPaths; readonly AmbiencePathConfig m_ambiencePaths; @@ -18,6 +20,7 @@ namespace OCES.Audio // 上一次匹配到的 PathId,用于 Transition 表的 FromPathId 查询 public uint LastMusicPathId { get; private set; } public uint LastAmbiencePathId { get; private set; } + internal IReadOnlyDictionary ActiveStates { get { return this.m_activeStates; }} public MusicStateRouter(MusicPathConfig musicPaths, AmbiencePathConfig ambiencePaths) { @@ -31,8 +34,8 @@ namespace OCES.Audio public void SetState(TEnum state, out uint musicContainerId, out uint ambienceContainerId) where TEnum : Enum { - // Dictionary 天然保证同一 StateGroup 只保留最新值,直接覆盖即可 - this.m_activeStates[typeof(TEnum)] = Convert.ToInt32(state); + // Dictionary 天然保证同一 StateGroup 只保留最新值,直接覆盖即可 + this.m_activeStates[typeof(TEnum)] = state; musicContainerId = MatchBestPath(this.m_musicPaths.MusicPathList(), out uint musicPathId); ambienceContainerId = MatchBestPath(this.m_ambiencePaths.AmbiencePathList(), out uint ambiencePathId); @@ -99,9 +102,9 @@ namespace OCES.Audio } bool conditionMet = false; - foreach (KeyValuePair kv in this.m_activeStates) + foreach (KeyValuePair kv in this.m_activeStates) { - if (StateGroupRegistry.GetTypeId(kv.Key) != typeId || kv.Value != stateValue) + if (StateGroupRegistry.GetTypeId(kv.Key) != typeId || Convert.ToInt32(kv.Value) != stateValue) continue; conditionMet = true; break; diff --git a/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs index cd14c61..10cfb7c 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using UnityEngine; namespace OCES.Audio @@ -20,6 +21,11 @@ namespace OCES.Audio // 记录上一次两个通道各自匹配到的 PathId,用于查 Transition 表 uint m_lastMusicPathId; uint m_lastAmbiencePathId; + + internal IReadOnlyDictionary ActiveStates + { + get { return this.m_stateRouter.ActiveStates; } + } internal void Initialize( MusicSegmentConfig segments, diff --git a/Assets/Scripts/OCES/Audio/HandWritten/SfxSystem.cs b/Assets/Scripts/OCES/Audio/HandWritten/SfxSystem.cs index d307afd..751fe10 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/SfxSystem.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/SfxSystem.cs @@ -2,6 +2,8 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using OCES.Audio.HandWritten; +using OCES.Haptic; using UnityEngine; using UnityEngine.Audio; @@ -33,6 +35,7 @@ namespace OCES.Audio AudioSourcePool m_pool; AudioContainerSelector m_containerSelector; PitchStepResolver m_pitchStepResolver; + VolumeStepResolver m_volumeStepResolver; #if UNITY_EDITOR void Update() @@ -74,6 +77,7 @@ namespace OCES.Audio this.m_pool = pool; this.m_containerSelector = new AudioContainerSelector(); this.m_pitchStepResolver = new PitchStepResolver(); + this.m_volumeStepResolver = new VolumeStepResolver(); AudioMixerGroup[] sfx = Find("Master/Regular/SFX"); if (sfx.Length > 0) this.m_sfxGroup = sfx[0]; @@ -173,7 +177,8 @@ namespace OCES.Audio // 执行播放 float pitch = this.m_pitchStepResolver.ResolvePitch(audioObject, now); //算一下用不用变调 - PlayNewSound(audioObject, pitch); + float volume = this.m_volumeStepResolver.ResolveVolume(audioObject, now); + PlayNewSound(audioObject, pitch, volume); this.m_lastPlayTime[audioObject.Id] = now; onPlay?.Invoke(); } @@ -182,12 +187,13 @@ namespace OCES.Audio // 播放逻辑 // ───────────────────────────────────────────── - void PlayNewSound(AudioObject audioObject, float pitch) + void PlayNewSound(AudioObject audioObject, float pitch, float volume) { ActiveSound active = new() { AudioObject = audioObject, Pitch = pitch, + Volume = volume, State = ActiveSoundState.Pending, StartTime = Time.realtimeSinceStartupAsDouble, }; @@ -207,7 +213,7 @@ namespace OCES.Audio /// /// 连续容器播放协程(Random / Sequence 持续模式) /// - IEnumerator PlayContainerContinuous(AudioSource source, AudioObject audioObject, ActiveSound chainActive, int startIndex, float pitch) + IEnumerator PlayContainerContinuous(AudioSource source, AudioObject audioObject, ActiveSound chainActive, int startIndex) { bool isRandom = audioObject.ContainerType == ContainerType.Random; @@ -229,7 +235,7 @@ namespace OCES.Audio limitRepetition); // 配置并播放 - if (!SetupSource(source, audioObject, pitch, index)) + if (!SetupSource(source, chainActive, index)) { Debug.LogError($"音频文件未找到:{audioObject.Name[index]}"); yield break; @@ -255,6 +261,7 @@ namespace OCES.Audio this.m_pool.ReturnToPool(source.gameObject); //Debug.Log($"[Container - Continuous] 协程正常结束: {audioObject.Name[0]}"); + // TryStopHaptic(audioObject.Haptic); yield break; } } @@ -334,8 +341,9 @@ namespace OCES.Audio return this.m_sfxGroup; } - bool SetupSource(AudioSource source, AudioObject audioObject, float pitch, int clipIndex = 0) + bool SetupSource(AudioSource source, ActiveSound activeSound, int clipIndex = 0) { + AudioObject audioObject = activeSound.AudioObject; AudioClip clip = Resources.Load($"Audios/{audioObject.Name[clipIndex]}"); // TODO 抽象同一资源加载接口 if (!clip) { @@ -347,7 +355,8 @@ namespace OCES.Audio source.loop = audioObject.LoopCount < 0; source.priority = audioObject.Priority; source.outputAudioMixerGroup = GetMixerGroup(audioObject.MixingType); - source.pitch = pitch; + source.pitch = activeSound.Pitch; + source.volume = activeSound.Volume; return true; } @@ -364,6 +373,15 @@ namespace OCES.Audio IncrementClipCount(activeSound.AudioObject.Id); } + if (activeSound.AudioObject.ContainerType == ContainerType.Blend) + { + Debug.LogWarning($"[Haptic System] Blend container {activeSound.AudioObject.Id} should not have haptic feedback!"); + } + else + { + TryStartHaptic(activeSound); + } + activeSound.Coroutine = StartCoroutine(RemoveWhenFinished(activeSound)); } @@ -371,6 +389,7 @@ namespace OCES.Audio { AudioObject audioObject = active.AudioObject; float pitch = active.Pitch; + float volume = active.Volume; // ======================= // Blend(每个clip一个ActiveSound) @@ -385,10 +404,11 @@ namespace OCES.Audio { AudioObject = audioObject, Pitch = pitch, - State = ActiveSoundState.Playing + Volume = volume, + State = ActiveSoundState.Playing, }; - if (!SetupSource(source, audioObject, pitch, i)) + if (!SetupSource(source, child, i)) { this.m_pool.ReturnToPool(source.gameObject); continue; @@ -424,7 +444,7 @@ namespace OCES.Audio int start = audioObject.ContainerType == ContainerType.Random ? -1 : 0; active.Coroutine = StartCoroutine( - PlayContainerContinuous(sourceSingle, audioObject, active, start, pitch) + PlayContainerContinuous(sourceSingle, audioObject, active, start) ); return; @@ -437,12 +457,12 @@ namespace OCES.Audio { ContainerType.Random => m_containerSelector.PickShuffleIndex(audioObject), ContainerType.Sequence => m_containerSelector.GetNextSequenceIndex(audioObject), - _ => 0 + _ => 0, }; - if (!SetupSource(sourceSingle, audioObject, pitch, index)) + if (!SetupSource(sourceSingle, active, index)) { - m_pool.ReturnToPool(sourceSingle.gameObject); + this.m_pool.ReturnToPool(sourceSingle.gameObject); return; } @@ -491,7 +511,17 @@ namespace OCES.Audio this.m_pool.ReturnToPool(active.Source.gameObject); } + static void TryStartHaptic(ActiveSound active) + { + uint hapticId = active.AudioObject.Haptic; + if (hapticId == 0) return; + HapticSystem.Instance.Play(hapticId, isDirectCall: false); + } + static void TryStopHaptic(uint hapticId) + { + HapticSystem.Instance.Stop(hapticId); + } } /// @@ -506,6 +536,7 @@ namespace OCES.Audio public int CurrentLoopCount; public Coroutine Coroutine; public float Pitch; + public float Volume; public ActiveSoundState State; } } \ No newline at end of file diff --git a/Assets/Scripts/OCES/Audio/HandWritten/VolumeStepResolver.cs b/Assets/Scripts/OCES/Audio/HandWritten/VolumeStepResolver.cs new file mode 100644 index 0000000..ae5e8ad --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/VolumeStepResolver.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OCES.Audio.HandWritten +{ + public class VolumeStepResolver + { + readonly Dictionary m_volumeStepCounts = new(); + readonly Dictionary m_volumeStepLastTime = new(); + + internal float ResolveVolume(AudioObject audioObject, double time) + { + // 计算一下配置的音量是多少 + float baseVolume = Mathf.Pow(10,audioObject.Volume / 20f); + + // 优化版。看看表现,要是确实Mathf.Pow造成性能卡点了就用这个。 + //float baseVolume = audioObject.Volume == 0 ? 1f : Mathf.Pow(10,audioObject.Volume / 20f); + + if (audioObject.VolumeStepThreshold == 0) //没配置VolumeStep + { + return baseVolume; + } + + // 超时了,或者没播过 + if (!this.m_volumeStepLastTime.TryGetValue(audioObject.Id, out double lastVolumeStepTime) + || time - lastVolumeStepTime > audioObject.VolumeStepThreshold) + { + this.m_volumeStepCounts[audioObject.Id] = 0; + this.m_volumeStepLastTime[audioObject.Id] = time; + return baseVolume; + } + + //命中了 + int volumeStepCount = this.m_volumeStepCounts[audioObject.Id]; + volumeStepCount = this.m_volumeStepCounts[audioObject.Id] = volumeStepCount + 1; + this.m_volumeStepLastTime[audioObject.Id] = time; + return Mathf.Clamp(Mathf.Pow(10, (audioObject.Volume + audioObject.VolumeStep * volumeStepCount) / 20f), 0f, 1f); + } + } +} diff --git a/Assets/Scripts/OCES/Audio/HandWritten/VolumeStepResolver.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/VolumeStepResolver.cs.meta new file mode 100644 index 0000000..008cac7 --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/VolumeStepResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0059d6fc851c474a97bc05f6385f9a48 +timeCreated: 1776067889 \ No newline at end of file diff --git a/Assets/Scripts/OCES/ButtonInvoker.cs b/Assets/Scripts/OCES/ButtonInvoker.cs index 7f1a878..ca9623f 100644 --- a/Assets/Scripts/OCES/ButtonInvoker.cs +++ b/Assets/Scripts/OCES/ButtonInvoker.cs @@ -7,7 +7,7 @@ namespace OCES { public class ButtonInvoker : MonoBehaviour { - public GameState targetGameState; + public TileMaterial targetGameState; public bool enableLowpass; Button m_button; diff --git a/Assets/Scripts/OCES/Haptic.meta b/Assets/Scripts/OCES/Haptic.meta new file mode 100644 index 0000000..abc744f --- /dev/null +++ b/Assets/Scripts/OCES/Haptic.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 042da115ae6c94eb59b52cb4537aa022 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/Haptic/Generated.meta b/Assets/Scripts/OCES/Haptic/Generated.meta new file mode 100644 index 0000000..3662395 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Generated.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 12705f55004c045a2ae82b5407a3cbbb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs b/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs new file mode 100644 index 0000000..c2e1876 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs @@ -0,0 +1,111 @@ +/* + * auto generated by tools(注意:千万不要手动修改本文件) + * HapticObject + */ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; + +namespace OCES.Haptic +{ +[Serializable] +public partial class HapticObject : IBinarySerializable +{ + /// + /// + /// + public uint Id { get; set; } + + /// + /// 类型 + /// + public HapticType Type { get; set; } + + /// + /// 强度 + /// + public float Amplitude { get; set; } + + /// + /// 尖锐度 + /// + public float Frequency { get; set; } + + /// + /// 时长 + /// + public float Duration { get; set; } + + /// + /// 播放来源 + /// + public string Payload { get; set; } + + /// + /// 回退预设 + /// + public string FallbackPreset { get; set; } + + + public void DeSerialize(BinaryReader reader) + { + Id = reader.ReadUInt32(); + Type = (HapticType)reader.ReadByte(); + Amplitude = reader.ReadSingle(); + Frequency = reader.ReadSingle(); + Duration = reader.ReadSingle(); + Payload = reader.ReadString(); + FallbackPreset = reader.ReadString(); + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(Id); + writer.Write((byte)Type); + writer.Write(Amplitude); + writer.Write(Frequency); + writer.Write(Duration); + writer.Write(Payload); + writer.Write(FallbackPreset); + } +} + +[Serializable] +public partial class HapticObjectConfig : IBinarySerializable +{ + Dictionary m_hapticObjectInfos = new(); + List m_hapticObjectInfoList; + + public List HapticObjectList() + { + this.m_hapticObjectInfoList ??= new List(this.m_hapticObjectInfos.Values); + return this.m_hapticObjectInfoList; + } + + public void DeSerialize(BinaryReader reader) + { + int count = reader.ReadInt32(); + for (int i = 0; i < count; i++) + { + HapticObject tempData = new(); + tempData.DeSerialize(reader); + this.m_hapticObjectInfos.Add(tempData.Id, tempData); + } + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(this.m_hapticObjectInfos.Count); + foreach (HapticObject hapticObject in this.m_hapticObjectInfos.Values) + { + hapticObject.Serialize(writer); + } + } + + public HapticObject QueryById(uint id) + { + return this.m_hapticObjectInfos.GetValueOrDefault(id); + } +} +} diff --git a/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs.meta b/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs.meta new file mode 100644 index 0000000..dbdee21 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57a231d8d4f5a433caa1316cd9b055ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/Haptic/Handwritten.meta b/Assets/Scripts/OCES/Haptic/Handwritten.meta new file mode 100644 index 0000000..093bc83 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9e1d12770ca114030b35c14f8c72b193 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs b/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs new file mode 100644 index 0000000..fa11f17 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs @@ -0,0 +1,46 @@ +using System.IO; + +namespace OCES.Haptic +{ + public interface IBinarySerializable + { + void DeSerialize(BinaryReader reader); + void Serialize(BinaryWriter writer); + } + + public enum HapticType + { + Preset = 0, //播放预制 + Emphasis = 1, //播放瞬时 + Constant = 2, //播放连续 + Advance = 3, //播放文件 + } + + /// + /// 文件操作类 + /// + public static class FileManager + { + /// + /// 从内存流中读取二进制 + /// + /// + /// + /// + public static bool ReadBinaryDataFromBytes(byte[] bytes, ref IBinarySerializable data) + { + if (bytes == null) + return false; + using (MemoryStream memoryStream = new(bytes)) + { + using (var br = new BinaryReader(memoryStream)) + { + data.DeSerialize(br); + br.Close(); + } + memoryStream.Close(); + } + return true; + } + } +} diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs.meta b/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs.meta new file mode 100644 index 0000000..e1e56a1 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d7267d262bcf45e0ba1855dccdc5e87e +timeCreated: 1775705326 \ No newline at end of file diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs new file mode 100644 index 0000000..47b7120 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Lofelt.NiceVibrations; +using UnityEngine; + +namespace OCES.Haptic +{ + public class HapticSystem : MonoBehaviour + { + public static HapticSystem Instance {get; private set;} + [NonSerialized] + public bool IsHapticSupported; + [NonSerialized] + public bool IsMeetsAdvanceRequirements; + + HapticObjectConfig m_hapticObjects; + const string k_hapticConfigPath = "HapticData/"; + const string k_hapticResourcesPath = "Haptics/"; + + public void Play(uint hapticId, bool isDirectCall = true) + { + HapticObject hapticObject = this.m_hapticObjects.QueryById(hapticId); + if (hapticObject != null) + { + Play(hapticObject); + if (isDirectCall) + { + Debug.LogWarning($"[Haptic System] Playing haptic id {hapticId} without play audio." + + "This method should only be called during debugging."); + } + } + else + { + Debug.LogError("[Haptic System] Could not find Haptic Object with id: " + hapticId); + } + + } + + public void Play(HapticObject hapticObject) + { + switch (hapticObject.Type) + { + case HapticType.Preset: + if (Enum.TryParse(hapticObject.Payload, out HapticPatterns.PresetType hapticPattern)) + { + HapticPatterns.PlayPreset(hapticPattern); + } + else + { + Debug.LogError($"[Haptic System] Could not parse haptic pattern: {hapticObject.Payload}]"); + } + break; + case HapticType.Emphasis: + if (hapticObject.Amplitude < 0f || hapticObject.Frequency < 0f) + { + Debug.LogWarning($"[Haptic System] Haptic {hapticObject.Id} have no amplitude or frequency." + + "Please check the datatable."); + break; + } + HapticPatterns.PlayEmphasis(hapticObject.Amplitude, hapticObject.Frequency); + break; + case HapticType.Constant: + if (hapticObject.Amplitude < 0f || hapticObject.Frequency < 0f || hapticObject.Duration < 0f) + { + Debug.LogWarning($"[Haptic System] Haptic {hapticObject.Id} have no amplitude, frequency or duration." + + "Please check the datatable."); + break; + } + HapticController.Stop(); + HapticPatterns.PlayConstant(hapticObject.Amplitude, hapticObject.Frequency, hapticObject.Duration); + break; + case HapticType.Advance: + if (Enum.TryParse(hapticObject.FallbackPreset, out HapticPatterns.PresetType fallbackPreset)) + { + HapticController.fallbackPreset = fallbackPreset; + HapticClip hapticClip = GetHapticClip(hapticObject); + if (hapticClip) + { + HapticController.Stop(); + HapticController.Play(hapticClip); + } + else + { + Debug.LogError($"[Haptic System] Could not parse haptic file: {hapticObject.Payload}"); + } + } + else + { + Debug.LogError($"[Haptic System] Could not parse fallback preset: {hapticObject.FallbackPreset}]"); + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + + } + + public void Stop(uint? hapticId = null) + { + HapticController.Stop(); + } + + void Awake() + { + if (Instance && Instance != this) + { + Destroy(gameObject); + return; + } + Instance = this; + DontDestroyOnLoad(gameObject); + + this.m_hapticObjects = HapticConfigLoader.Load(k_hapticConfigPath + "HapticObject"); + this.IsHapticSupported = DeviceCapabilities.isVersionSupported; + this.IsMeetsAdvanceRequirements = DeviceCapabilities.meetsAdvancedRequirements; + } + + static HapticClip GetHapticClip(HapticObject hapticObject) + { + return Resources.Load(k_hapticResourcesPath + hapticObject.Payload); + } + + static class HapticConfigLoader + { + internal static T Load(string tableName) where T : IBinarySerializable, new() + { + TextAsset bytes = Resources.Load(tableName); + if (!bytes) + Debug.LogError($"未找到表 {tableName}"); + IBinarySerializable data = new T(); + bool readOk = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data); + if (readOk) + return (T)data; + Debug.LogError($"{tableName} 解析出错,类型 {typeof(T)}"); + return default; + } + } + } +} diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs.meta b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs.meta new file mode 100644 index 0000000..4f73853 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b1939bb20b5db46c1a5f7354ca0fba87 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OCES/PlaySoundBind.cs b/Assets/Scripts/OCES/PlaySoundBind.cs new file mode 100644 index 0000000..feffb87 --- /dev/null +++ b/Assets/Scripts/OCES/PlaySoundBind.cs @@ -0,0 +1,17 @@ +using System.Collections; +using System.Collections.Generic; +using OCES.Audio; +using UnityEngine; +using UnityEngine.UI; + +public class PlaySoundBind : MonoBehaviour +{ + + public InputField inputField; + + public void OnButtonPressed() + { + uint.TryParse(this.inputField.text, out uint hapticId); + AudioSystem.Instance.Play(hapticId); + } +} diff --git a/Assets/Scripts/OCES/PlaySoundBind.cs.meta b/Assets/Scripts/OCES/PlaySoundBind.cs.meta new file mode 100644 index 0000000..5698d7c --- /dev/null +++ b/Assets/Scripts/OCES/PlaySoundBind.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3bdbaddf2c05142e19686a9a82ef92c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/UniversalRP.asset b/Assets/Settings/UniversalRP.asset index 01b1944..2d71863 100644 --- a/Assets/Settings/UniversalRP.asset +++ b/Assets/Settings/UniversalRP.asset @@ -32,6 +32,7 @@ MonoBehaviour: m_FsrSharpness: 0.92 m_EnableLODCrossFade: 1 m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 m_MainLightRenderingMode: 1 m_MainLightShadowsSupported: 1 m_MainLightShadowmapResolution: 2048 @@ -52,9 +53,11 @@ MonoBehaviour: m_CascadeBorder: 0.1 m_ShadowDepthBias: 1 m_ShadowNormalBias: 1 + m_AnyShadowsSupported: 1 m_SoftShadowsSupported: 0 m_ConservativeEnclosingSphere: 0 m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 m_AdditionalLightsCookieResolution: 2048 m_AdditionalLightsCookieFormat: 3 m_UseSRPBatcher: 1 @@ -69,6 +72,7 @@ MonoBehaviour: m_ColorGradingMode: 0 m_ColorGradingLutSize: 32 m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 m_ShadowType: 1 m_LocalShadowsSupported: 0 m_LocalShadowsAtlasResolution: 256 @@ -78,5 +82,33 @@ MonoBehaviour: m_Textures: blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_PrefilteringModeMainLightShadows: 4 + m_PrefilteringModeAdditionalLight: 4 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 diff --git a/ProjectSettings/AudioManager.asset b/ProjectSettings/AudioManager.asset index fe9c738..90312f7 100644 --- a/ProjectSettings/AudioManager.asset +++ b/ProjectSettings/AudioManager.asset @@ -8,8 +8,8 @@ AudioManager: Rolloff Scale: 1 Doppler Factor: 1 Default Speaker Mode: 2 - m_SampleRate: 0 - m_DSPBufferSize: 1024 + m_SampleRate: 48000 + m_DSPBufferSize: 256 m_VirtualVoiceCount: 512 m_RealVoiceCount: 32 m_EnableOutputSuspension: 0 @@ -17,4 +17,4 @@ AudioManager: m_AmbisonicDecoderPlugin: m_DisableAudio: 0 m_VirtualizeEffects: 1 - m_RequestedDSPBufferSize: 0 + m_RequestedDSPBufferSize: 256 diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 8ef5e6c..ee95d97 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -12,7 +12,7 @@ PlayerSettings: targetDevice: 2 useOnDemandResources: 0 accelerometerFrequency: 60 - companyName: DefaultCompany + companyName: oces productName: AudioSystem defaultCursor: {fileID: 0} cursorHotspot: {x: 0, y: 0} @@ -163,8 +163,9 @@ PlayerSettings: androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 applicationIdentifier: - Android: com.DefaultCompany.AudioSystem + Android: com.oces.AudioSystem Standalone: com.DefaultCompany.AudioSystem + iPhone: com.oces.AudioSystem buildNumber: Standalone: 0 VisionOS: 0 @@ -264,7 +265,7 @@ PlayerSettings: useCustomGradlePropertiesTemplate: 0 useCustomGradleSettingsTemplate: 0 useCustomProguardFile: 0 - AndroidTargetArchitectures: 1 + AndroidTargetArchitectures: 2 AndroidTargetDevices: 0 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} @@ -779,7 +780,8 @@ PlayerSettings: tvOS: DOTWEEN additionalCompilerArguments: {} platformArchitecture: {} - scriptingBackend: {} + scriptingBackend: + Android: 1 il2cppCompilerConfiguration: {} il2cppCodeGeneration: {} managedStrippingLevel: