migrate changes from audio system
This commit is contained in:
@@ -842,6 +842,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b1939bb20b5db46c1a5f7354ca0fba87, type: 3}
|
m_Script: {fileID: 11500000, guid: b1939bb20b5db46c1a5f7354ca0fba87, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
hapticSettings: {fileID: 11400000, guid: 84578921d0f5c46718f1826c55c7856a, type: 2}
|
||||||
--- !u!4 &1279932963
|
--- !u!4 &1279932963
|
||||||
Transform:
|
Transform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 05675e28900a24c18b737120397c881a
|
guid: 12705f55004c045a2ae82b5407a3cbbb
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 1a53a6b5d02fb40e4bd2de8e2c6ffa27
|
guid: 57a231d8d4f5a433caa1316cd9b055ae
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e681c729026b4fdf83b38f1824f4ab02
|
||||||
|
timeCreated: 1778761511
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace OCES.Haptic.Editor
|
||||||
|
{
|
||||||
|
static class HapticSettingsProvider
|
||||||
|
{
|
||||||
|
const string k_settingPath = "Assets/Settings/HapticSettings.asset";
|
||||||
|
|
||||||
|
[SettingsProvider]
|
||||||
|
static SettingsProvider Creat()
|
||||||
|
{
|
||||||
|
return new SettingsProvider("Project/Haptic Settings", SettingsScope.Project)
|
||||||
|
{
|
||||||
|
label = "Haptic Settings",
|
||||||
|
guiHandler = _ =>
|
||||||
|
{
|
||||||
|
HapticSettings settings = AssetDatabase.LoadAssetAtPath<HapticSettings>(k_settingPath);
|
||||||
|
if (!settings)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
$"未找到 AudioExtendSettings.asset\n期望路径: {k_settingPath}",
|
||||||
|
MessageType.Warning);
|
||||||
|
if (GUILayout.Button("创建默认配置"))
|
||||||
|
CreateDefaultAsset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerializedObject serializedObject = new(settings);
|
||||||
|
SerializedProperty serializedProperty = serializedObject.GetIterator();
|
||||||
|
serializedProperty.NextVisible(true);
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
while (serializedProperty.NextVisible(false))
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(serializedProperty, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
EditorUtility.SetDirty(settings);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keywords = new[] { "Haptic", "Audio", "Vibration", "Vibrator", "Path" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Tools/Haptic/Create Haptic Settings Asset")]
|
||||||
|
static void CreateDefaultAsset()
|
||||||
|
{
|
||||||
|
if (!AssetDatabase.IsValidFolder("Assets/Settings"))
|
||||||
|
AssetDatabase.CreateFolder("Assets", "Settings");
|
||||||
|
|
||||||
|
HapticSettings asset = ScriptableObject.CreateInstance<HapticSettings>();
|
||||||
|
AssetDatabase.CreateAsset(asset, k_settingPath);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
Debug.Log($"[HapticSettings] 已创建默认配置:{k_settingPath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fd277ab8102549be90d99031ceb8193a
|
||||||
|
timeCreated: 1778761525
|
||||||
@@ -31,12 +31,15 @@ namespace OCES.Haptic
|
|||||||
{
|
{
|
||||||
if (bytes == null)
|
if (bytes == null)
|
||||||
return false;
|
return false;
|
||||||
using MemoryStream memoryStream = new(bytes);
|
using (MemoryStream memoryStream = new(bytes))
|
||||||
using (BinaryReader br = new(memoryStream))
|
|
||||||
{
|
{
|
||||||
data.DeSerialize(br);
|
using (var br = new BinaryReader(memoryStream))
|
||||||
|
{
|
||||||
|
data.DeSerialize(br);
|
||||||
|
br.Close();
|
||||||
|
}
|
||||||
|
memoryStream.Close();
|
||||||
}
|
}
|
||||||
memoryStream.Close();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace OCES.Haptic
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 触感反馈系统扩展配置,集中管理所有路径和可调参数。
|
||||||
|
/// 资产位置:Assets/Resources/AudioExtendSettings.asset
|
||||||
|
/// 编辑入口:Project Settings > Audio Extend
|
||||||
|
/// </summary>
|
||||||
|
public class HapticSettings : ScriptableObject
|
||||||
|
{
|
||||||
|
[Tooltip("Resources 子目录:触感配置文件")]
|
||||||
|
public string hapticConfigPath = "HapticData/";
|
||||||
|
|
||||||
|
[Tooltip("Resources 子目录:触感资源文件(.haptic)")]
|
||||||
|
public string hapticResourcePath = "Haptics/";
|
||||||
|
|
||||||
|
public static HapticSettings Instance { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cf447f41468045bf9789408bd135ebeb
|
||||||
|
timeCreated: 1778750228
|
||||||
@@ -10,22 +10,19 @@ namespace OCES.Haptic
|
|||||||
{
|
{
|
||||||
public static HapticSystem Instance {get; private set;}
|
public static HapticSystem Instance {get; private set;}
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public bool IsHapticSupported = DeviceCapabilities.isVersionSupported;
|
public bool IsHapticSupported;
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public bool IsMeetsAdvanceRequirements = DeviceCapabilities.meetsAdvancedRequirements;
|
public bool IsMeetsAdvanceRequirements;
|
||||||
|
[SerializeField]
|
||||||
|
HapticSettings hapticSettings;
|
||||||
|
|
||||||
|
|
||||||
|
internal ResourceLoader ResourceLoader;
|
||||||
|
|
||||||
HapticObjectConfig m_hapticObjects;
|
HapticObjectConfig m_hapticObjects;
|
||||||
const string k_hapticConfigPath = "HapticData/";
|
|
||||||
const string k_hapticResourcesPath = "Haptics/";
|
|
||||||
|
|
||||||
public void Play(uint hapticId, bool isDirectCall = true)
|
public void Play(uint hapticId, bool isDirectCall = true)
|
||||||
{
|
{
|
||||||
if (this.m_hapticObjects is null)
|
|
||||||
{
|
|
||||||
Debug.LogError($"[Haptic System] Config not loaded!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HapticObject hapticObject = this.m_hapticObjects.QueryById(hapticId);
|
HapticObject hapticObject = this.m_hapticObjects.QueryById(hapticId);
|
||||||
if (hapticObject != null)
|
if (hapticObject != null)
|
||||||
{
|
{
|
||||||
@@ -58,7 +55,7 @@ namespace OCES.Haptic
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HapticType.Emphasis:
|
case HapticType.Emphasis:
|
||||||
if (hapticObject.Amplitude <= 0f || hapticObject.Frequency <= 0f)
|
if (hapticObject.Amplitude < 0f || hapticObject.Frequency < 0f)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[Haptic System] Haptic {hapticObject.Id} have no amplitude or frequency." +
|
Debug.LogWarning($"[Haptic System] Haptic {hapticObject.Id} have no amplitude or frequency." +
|
||||||
"Please check the datatable.");
|
"Please check the datatable.");
|
||||||
@@ -67,7 +64,7 @@ namespace OCES.Haptic
|
|||||||
HapticPatterns.PlayEmphasis(hapticObject.Amplitude, hapticObject.Frequency);
|
HapticPatterns.PlayEmphasis(hapticObject.Amplitude, hapticObject.Frequency);
|
||||||
break;
|
break;
|
||||||
case HapticType.Constant:
|
case HapticType.Constant:
|
||||||
if (hapticObject.Amplitude <= 0f || hapticObject.Frequency <= 0f || hapticObject.Duration <= 0f)
|
if (hapticObject.Amplitude < 0f || hapticObject.Frequency < 0f || hapticObject.Duration < 0f)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[Haptic System] Haptic {hapticObject.Id} have no amplitude, frequency or duration." +
|
Debug.LogWarning($"[Haptic System] Haptic {hapticObject.Id} have no amplitude, frequency or duration." +
|
||||||
"Please check the datatable.");
|
"Please check the datatable.");
|
||||||
@@ -79,10 +76,10 @@ namespace OCES.Haptic
|
|||||||
case HapticType.Advance:
|
case HapticType.Advance:
|
||||||
if (Enum.TryParse(hapticObject.FallbackPreset, out HapticPatterns.PresetType fallbackPreset))
|
if (Enum.TryParse(hapticObject.FallbackPreset, out HapticPatterns.PresetType fallbackPreset))
|
||||||
{
|
{
|
||||||
|
HapticController.fallbackPreset = fallbackPreset;
|
||||||
HapticClip hapticClip = GetHapticClip(hapticObject);
|
HapticClip hapticClip = GetHapticClip(hapticObject);
|
||||||
if (hapticClip)
|
if (hapticClip)
|
||||||
{
|
{
|
||||||
HapticController.fallbackPreset = fallbackPreset;
|
|
||||||
HapticController.Stop();
|
HapticController.Stop();
|
||||||
HapticController.Play(hapticClip);
|
HapticController.Play(hapticClip);
|
||||||
}
|
}
|
||||||
@@ -109,6 +106,8 @@ namespace OCES.Haptic
|
|||||||
|
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
|
HapticSettings.Instance = this.hapticSettings;
|
||||||
|
|
||||||
if (Instance && Instance != this)
|
if (Instance && Instance != this)
|
||||||
{
|
{
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
@@ -117,31 +116,28 @@ namespace OCES.Haptic
|
|||||||
Instance = this;
|
Instance = this;
|
||||||
DontDestroyOnLoad(gameObject);
|
DontDestroyOnLoad(gameObject);
|
||||||
|
|
||||||
this.m_hapticObjects = HapticConfigLoader.Load<HapticObjectConfig>(k_hapticConfigPath + "HapticObject");
|
this.ResourceLoader = gameObject.AddComponent<ResourceLoader>();
|
||||||
}
|
|
||||||
|
|
||||||
void OnDestroy()
|
this.m_hapticObjects = HapticConfigLoader.Load<HapticObjectConfig>(HapticSettings.Instance.hapticConfigPath + "HapticObject");
|
||||||
{
|
this.IsHapticSupported = DeviceCapabilities.isVersionSupported;
|
||||||
if (Instance == this) Instance = null;
|
this.IsMeetsAdvanceRequirements = DeviceCapabilities.meetsAdvancedRequirements;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HapticClip GetHapticClip(HapticObject hapticObject)
|
static HapticClip GetHapticClip(HapticObject hapticObject)
|
||||||
{
|
{
|
||||||
return Resources.Load<HapticClip>(k_hapticResourcesPath + hapticObject.Payload);
|
return Instance.ResourceLoader.LoadSync<HapticClip>(HapticSettings.Instance.hapticResourcePath + hapticObject.Payload);
|
||||||
//TODO: cache HapticClips into a Dictionary<string, HapticClip> or using AsyncLoad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class HapticConfigLoader
|
static class HapticConfigLoader
|
||||||
{
|
{
|
||||||
internal static T Load<T>(string tableName) where T : IBinarySerializable, new()
|
internal static T Load<T>(string tableName) where T : IBinarySerializable, new()
|
||||||
{
|
{
|
||||||
TextAsset bytes = Resources.Load<TextAsset>(tableName);
|
TextAsset bytes = Instance.ResourceLoader.LoadSync<TextAsset>(tableName);
|
||||||
if (!bytes)
|
if (!bytes)
|
||||||
{
|
{
|
||||||
Debug.LogError($"未找到表 {tableName}");
|
Debug.LogError($"未找到表 {tableName}");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
IBinarySerializable data = new T();
|
IBinarySerializable data = new T();
|
||||||
bool readOk = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data);
|
bool readOk = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data);
|
||||||
if (readOk)
|
if (readOk)
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace OCES
|
||||||
|
{
|
||||||
|
public class ResourceLoader : MonoBehaviour
|
||||||
|
{
|
||||||
|
readonly Dictionary<string, Object> m_cachedObjects = new();
|
||||||
|
readonly Dictionary<string, List<Action<Object>>> m_pendingCallbacks = new();
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
internal T LoadSync<T>(string path) where T : Object
|
||||||
|
{
|
||||||
|
if (this.m_cachedObjects.TryGetValue(path, out Object cachedObject))
|
||||||
|
{
|
||||||
|
return cachedObject as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
T newObject = Resources.Load<T>(path);
|
||||||
|
this.m_cachedObjects.Add(path, newObject);
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void LoadAsync<T>(string path, Action<T> onComplete) where T : Object
|
||||||
|
{
|
||||||
|
if (this.m_cachedObjects.TryGetValue(path, out Object cachedObject))
|
||||||
|
{
|
||||||
|
onComplete?.Invoke(cachedObject as T);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.m_pendingCallbacks.TryGetValue(path, out List<Action<Object>> callbacks))
|
||||||
|
{
|
||||||
|
callbacks.Add(obj => onComplete?.Invoke(obj as T));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.m_pendingCallbacks[path] = new List<Action<Object>> { obj => onComplete?.Invoke(obj as T) };
|
||||||
|
ResourceRequest newRequest = Resources.LoadAsync<T>(path);
|
||||||
|
StartCoroutine(HandleAsyncLoadCompletion(path, newRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator HandleAsyncLoadCompletion(string path, ResourceRequest request)
|
||||||
|
{
|
||||||
|
yield return request;
|
||||||
|
|
||||||
|
if (request.asset)
|
||||||
|
{
|
||||||
|
this.m_cachedObjects[path] = request.asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.m_pendingCallbacks.Remove(path, out List<Action<Object>> callbacks))
|
||||||
|
{
|
||||||
|
foreach (Action<Object> callback in callbacks)
|
||||||
|
{
|
||||||
|
callback?.Invoke(request.asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PreloadAsync<T>(string[] paths)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Release<T>(string path)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ReleaseUnused()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 845d98765be843f9a943f41f45cdf013
|
||||||
|
timeCreated: 1778573329
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 508434b1d13bc42879e0033e2fbde015
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: cf447f41468045bf9789408bd135ebeb, type: 3}
|
||||||
|
m_Name: HapticSettings
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
hapticConfigPath: HapticData/
|
||||||
|
hapticResourcePath: Haptics/
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 84578921d0f5c46718f1826c55c7856a
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Reference in New Issue
Block a user