From 32be8f5887766b84d2881f7e9c8378bdc455a11d Mon Sep 17 00:00:00 2001 From: Oliver Wong Date: Thu, 14 May 2026 20:50:43 +0800 Subject: [PATCH] migrate changes from audio system --- Assets/Scenes/HomeScene.unity | 1 + Assets/Scripts/OCES/Haptic/Generated.meta | 2 +- .../Haptic/Generated/HapticObject.cs.meta | 2 +- .../OCES/Haptic/Handwritten/Editor.meta | 3 + .../Editor/HapticSettingsProvider.cs | 62 ++++++++++++++ .../Editor/HapticSettingsProvider.cs.meta | 3 + .../Handwritten/HandwrittenDefinitions.cs | 11 ++- .../OCES/Haptic/Handwritten/HapticSettings.cs | 20 +++++ .../Haptic/Handwritten/HapticSettings.cs.meta | 3 + .../OCES/Haptic/Handwritten/HapticSystem.cs | 44 +++++----- Assets/Scripts/OCES/ResourceLoader.cs | 80 +++++++++++++++++++ Assets/Scripts/OCES/ResourceLoader.cs.meta | 3 + Assets/Settings.meta | 8 ++ Assets/Settings/HapticSettings.asset | 16 ++++ Assets/Settings/HapticSettings.asset.meta | 8 ++ 15 files changed, 236 insertions(+), 30 deletions(-) create mode 100644 Assets/Scripts/OCES/Haptic/Handwritten/Editor.meta create mode 100644 Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs create mode 100644 Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs.meta create mode 100644 Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs create mode 100644 Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs.meta create mode 100644 Assets/Scripts/OCES/ResourceLoader.cs create mode 100644 Assets/Scripts/OCES/ResourceLoader.cs.meta create mode 100644 Assets/Settings.meta create mode 100644 Assets/Settings/HapticSettings.asset create mode 100644 Assets/Settings/HapticSettings.asset.meta diff --git a/Assets/Scenes/HomeScene.unity b/Assets/Scenes/HomeScene.unity index c03b503..05fe00d 100644 --- a/Assets/Scenes/HomeScene.unity +++ b/Assets/Scenes/HomeScene.unity @@ -842,6 +842,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b1939bb20b5db46c1a5f7354ca0fba87, type: 3} m_Name: m_EditorClassIdentifier: + hapticSettings: {fileID: 11400000, guid: 84578921d0f5c46718f1826c55c7856a, type: 2} --- !u!4 &1279932963 Transform: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/OCES/Haptic/Generated.meta b/Assets/Scripts/OCES/Haptic/Generated.meta index 365e4c2..3662395 100644 --- a/Assets/Scripts/OCES/Haptic/Generated.meta +++ b/Assets/Scripts/OCES/Haptic/Generated.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 05675e28900a24c18b737120397c881a +guid: 12705f55004c045a2ae82b5407a3cbbb folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs.meta b/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs.meta index 915c8a4..dbdee21 100644 --- a/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs.meta +++ b/Assets/Scripts/OCES/Haptic/Generated/HapticObject.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1a53a6b5d02fb40e4bd2de8e2c6ffa27 +guid: 57a231d8d4f5a433caa1316cd9b055ae MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/Editor.meta b/Assets/Scripts/OCES/Haptic/Handwritten/Editor.meta new file mode 100644 index 0000000..893a127 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e681c729026b4fdf83b38f1824f4ab02 +timeCreated: 1778761511 \ No newline at end of file diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs b/Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs new file mode 100644 index 0000000..76ded9b --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs @@ -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(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(); + AssetDatabase.CreateAsset(asset, k_settingPath); + AssetDatabase.SaveAssets(); + Debug.Log($"[HapticSettings] 已创建默认配置:{k_settingPath}"); + } + } +} diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs.meta b/Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs.meta new file mode 100644 index 0000000..e941a08 --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/Editor/HapticSettingsProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fd277ab8102549be90d99031ceb8193a +timeCreated: 1778761525 \ No newline at end of file diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs b/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs index 72949c8..fa11f17 100644 --- a/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HandwrittenDefinitions.cs @@ -31,12 +31,15 @@ namespace OCES.Haptic { if (bytes == null) return false; - using MemoryStream memoryStream = new(bytes); - using (BinaryReader br = new(memoryStream)) + using (MemoryStream memoryStream = new(bytes)) { - data.DeSerialize(br); + using (var br = new BinaryReader(memoryStream)) + { + data.DeSerialize(br); + br.Close(); + } + memoryStream.Close(); } - memoryStream.Close(); return true; } } diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs new file mode 100644 index 0000000..60be75c --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace OCES.Haptic +{ + /// + /// 触感反馈系统扩展配置,集中管理所有路径和可调参数。 + /// 资产位置:Assets/Resources/AudioExtendSettings.asset + /// 编辑入口:Project Settings > Audio Extend + /// + public class HapticSettings : ScriptableObject + { + [Tooltip("Resources 子目录:触感配置文件")] + public string hapticConfigPath = "HapticData/"; + + [Tooltip("Resources 子目录:触感资源文件(.haptic)")] + public string hapticResourcePath = "Haptics/"; + + public static HapticSettings Instance { get; internal set; } + } +} diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs.meta b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs.meta new file mode 100644 index 0000000..08e644e --- /dev/null +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cf447f41468045bf9789408bd135ebeb +timeCreated: 1778750228 \ No newline at end of file diff --git a/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs index 3cafd75..3313012 100644 --- a/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs +++ b/Assets/Scripts/OCES/Haptic/Handwritten/HapticSystem.cs @@ -10,22 +10,19 @@ namespace OCES.Haptic { public static HapticSystem Instance {get; private set;} [NonSerialized] - public bool IsHapticSupported = DeviceCapabilities.isVersionSupported; + public bool IsHapticSupported; [NonSerialized] - public bool IsMeetsAdvanceRequirements = DeviceCapabilities.meetsAdvancedRequirements; + public bool IsMeetsAdvanceRequirements; + [SerializeField] + HapticSettings hapticSettings; + + + internal ResourceLoader ResourceLoader; HapticObjectConfig m_hapticObjects; - const string k_hapticConfigPath = "HapticData/"; - const string k_hapticResourcesPath = "Haptics/"; - + 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); if (hapticObject != null) { @@ -58,7 +55,7 @@ namespace OCES.Haptic } break; 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." + "Please check the datatable."); @@ -67,7 +64,7 @@ namespace OCES.Haptic HapticPatterns.PlayEmphasis(hapticObject.Amplitude, hapticObject.Frequency); break; 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." + "Please check the datatable."); @@ -79,10 +76,10 @@ namespace OCES.Haptic case HapticType.Advance: if (Enum.TryParse(hapticObject.FallbackPreset, out HapticPatterns.PresetType fallbackPreset)) { + HapticController.fallbackPreset = fallbackPreset; HapticClip hapticClip = GetHapticClip(hapticObject); if (hapticClip) { - HapticController.fallbackPreset = fallbackPreset; HapticController.Stop(); HapticController.Play(hapticClip); } @@ -109,6 +106,8 @@ namespace OCES.Haptic void Awake() { + HapticSettings.Instance = this.hapticSettings; + if (Instance && Instance != this) { Destroy(gameObject); @@ -116,32 +115,29 @@ namespace OCES.Haptic } Instance = this; DontDestroyOnLoad(gameObject); + + this.ResourceLoader = gameObject.AddComponent(); - this.m_hapticObjects = HapticConfigLoader.Load(k_hapticConfigPath + "HapticObject"); - } - - void OnDestroy() - { - if (Instance == this) Instance = null; + this.m_hapticObjects = HapticConfigLoader.Load(HapticSettings.Instance.hapticConfigPath + "HapticObject"); + this.IsHapticSupported = DeviceCapabilities.isVersionSupported; + this.IsMeetsAdvanceRequirements = DeviceCapabilities.meetsAdvancedRequirements; } static HapticClip GetHapticClip(HapticObject hapticObject) { - return Resources.Load(k_hapticResourcesPath + hapticObject.Payload); - //TODO: cache HapticClips into a Dictionary or using AsyncLoad + return Instance.ResourceLoader.LoadSync(HapticSettings.Instance.hapticResourcePath + hapticObject.Payload); } static class HapticConfigLoader { internal static T Load(string tableName) where T : IBinarySerializable, new() { - TextAsset bytes = Resources.Load(tableName); + TextAsset bytes = Instance.ResourceLoader.LoadSync(tableName); if (!bytes) { Debug.LogError($"未找到表 {tableName}"); return default; } - IBinarySerializable data = new T(); bool readOk = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data); if (readOk) diff --git a/Assets/Scripts/OCES/ResourceLoader.cs b/Assets/Scripts/OCES/ResourceLoader.cs new file mode 100644 index 0000000..fbaac74 --- /dev/null +++ b/Assets/Scripts/OCES/ResourceLoader.cs @@ -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 m_cachedObjects = new(); + readonly Dictionary>> m_pendingCallbacks = new(); + + [CanBeNull] + internal T LoadSync(string path) where T : Object + { + if (this.m_cachedObjects.TryGetValue(path, out Object cachedObject)) + { + return cachedObject as T; + } + + T newObject = Resources.Load(path); + this.m_cachedObjects.Add(path, newObject); + return newObject; + } + + internal void LoadAsync(string path, Action 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> callbacks)) + { + callbacks.Add(obj => onComplete?.Invoke(obj as T)); + return; + } + + this.m_pendingCallbacks[path] = new List> { obj => onComplete?.Invoke(obj as T) }; + ResourceRequest newRequest = Resources.LoadAsync(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> callbacks)) + { + foreach (Action callback in callbacks) + { + callback?.Invoke(request.asset); + } + } + } + + internal void PreloadAsync(string[] paths) + { + + } + + internal void Release(string path) + { + + } + + internal void ReleaseUnused() + { + + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OCES/ResourceLoader.cs.meta b/Assets/Scripts/OCES/ResourceLoader.cs.meta new file mode 100644 index 0000000..44aa882 --- /dev/null +++ b/Assets/Scripts/OCES/ResourceLoader.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 845d98765be843f9a943f41f45cdf013 +timeCreated: 1778573329 \ No newline at end of file diff --git a/Assets/Settings.meta b/Assets/Settings.meta new file mode 100644 index 0000000..64706a7 --- /dev/null +++ b/Assets/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 508434b1d13bc42879e0033e2fbde015 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/HapticSettings.asset b/Assets/Settings/HapticSettings.asset new file mode 100644 index 0000000..fa7b82d --- /dev/null +++ b/Assets/Settings/HapticSettings.asset @@ -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/ diff --git a/Assets/Settings/HapticSettings.asset.meta b/Assets/Settings/HapticSettings.asset.meta new file mode 100644 index 0000000..574e71c --- /dev/null +++ b/Assets/Settings/HapticSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 84578921d0f5c46718f1826c55c7856a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: