[Optimization] TimerService&TimerDebug&AudioService
[Optimization] TimerService&TimerDebug&AudioService
This commit is contained in:
parent
a74715b468
commit
f4f0ea1754
@ -13,7 +13,6 @@ namespace AlicizaX.Audio.Editor
|
||||
private readonly AudioCategoryDebugInfo _categoryInfo = new AudioCategoryDebugInfo();
|
||||
private readonly AudioAgentDebugInfo _agentInfo = new AudioAgentDebugInfo();
|
||||
private readonly AudioClipCacheDebugInfo _clipCacheInfo = new AudioClipCacheDebugInfo();
|
||||
private SerializedProperty m_InstanceRoot = null;
|
||||
private SerializedProperty m_AudioListener = null;
|
||||
private SerializedProperty m_AudioMixer = null;
|
||||
private SerializedProperty m_AudioGroupConfigs = null;
|
||||
@ -31,7 +30,6 @@ namespace AlicizaX.Audio.Editor
|
||||
|
||||
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode);
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_InstanceRoot);
|
||||
EditorGUILayout.PropertyField(m_AudioListener, AudioListenerLabel);
|
||||
EditorGUILayout.PropertyField(m_AudioMixer);
|
||||
EditorGUILayout.PropertyField(m_AudioGroupConfigs, GroupConfigLabel);
|
||||
@ -51,7 +49,6 @@ namespace AlicizaX.Audio.Editor
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_InstanceRoot = serializedObject.FindProperty("m_InstanceRoot");
|
||||
m_AudioListener = serializedObject.FindProperty("m_AudioListener");
|
||||
m_AudioMixer = serializedObject.FindProperty("m_AudioMixer");
|
||||
m_AudioGroupConfigs = serializedObject.FindProperty("m_AudioGroupConfigs");
|
||||
|
||||
8
Editor/Timer.meta
Normal file
8
Editor/Timer.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5eec662629e81c458ff9c776e1a9e29
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
169
Editor/Timer/TimerComponentInspector.cs
Normal file
169
Editor/Timer/TimerComponentInspector.cs
Normal file
@ -0,0 +1,169 @@
|
||||
using AlicizaX.Editor;
|
||||
using AlicizaX.Timer.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Timer.Editor
|
||||
{
|
||||
[CustomEditor(typeof(TimerComponent))]
|
||||
internal sealed class TimerComponentInspector : GameFrameworkInspector
|
||||
{
|
||||
private const double UPDATE_INTERVAL = 0.001d;
|
||||
private const int MAX_DISPLAY_COUNT = 20;
|
||||
|
||||
private TimerDebugInfo[] _timerBuffer;
|
||||
#if UNITY_EDITOR
|
||||
private TimerDebugInfo[] _leakBuffer;
|
||||
#endif
|
||||
private double _lastUpdateTime;
|
||||
private int _cachedActiveCount;
|
||||
private int _cachedPoolCapacity;
|
||||
private int _cachedPeakActiveCount;
|
||||
private int _cachedFreeCount;
|
||||
private string _cachedUsageText;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
serializedObject.Update();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
DrawRuntimeDebugInfo();
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
double currentTime = EditorApplication.timeSinceStartup;
|
||||
if (currentTime - _lastUpdateTime >= UPDATE_INTERVAL)
|
||||
{
|
||||
_lastUpdateTime = currentTime;
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawRuntimeDebugInfo()
|
||||
{
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Available during runtime only.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AppServices.TryGet<ITimerService>(out ITimerService timerService))
|
||||
{
|
||||
EditorGUILayout.HelpBox("Timer service is not initialized.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timerService is not ITimerServiceDebugView debugView)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
debugView.GetStatistics(out _cachedActiveCount, out _cachedPoolCapacity, out _cachedPeakActiveCount, out _cachedFreeCount);
|
||||
_cachedUsageText = _cachedPoolCapacity > 0
|
||||
? Utility.Text.Format("{0:F1}%", (float)_cachedActiveCount / _cachedPoolCapacity * 100f)
|
||||
: "0.0%";
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Runtime Debug", EditorStyles.boldLabel);
|
||||
EditorGUILayout.LabelField("Active Timers", _cachedActiveCount.ToString());
|
||||
EditorGUILayout.LabelField("Pool Capacity", _cachedPoolCapacity.ToString());
|
||||
EditorGUILayout.LabelField("Peak Active Count", _cachedPeakActiveCount.ToString());
|
||||
EditorGUILayout.LabelField("Free Slots", _cachedFreeCount.ToString());
|
||||
EditorGUILayout.LabelField("Pool Usage", _cachedUsageText);
|
||||
|
||||
DrawTimerList(debugView, _cachedActiveCount);
|
||||
#if UNITY_EDITOR
|
||||
DrawLeakDetection(debugView, _cachedActiveCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void DrawTimerList(ITimerServiceDebugView debugView, int activeCount)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Active Timers", EditorStyles.boldLabel);
|
||||
|
||||
if (activeCount <= 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("No active timers.");
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTimerBuffer(activeCount);
|
||||
int timerCount = debugView.GetAllTimers(_timerBuffer);
|
||||
int displayCount = Mathf.Min(timerCount, MAX_DISPLAY_COUNT);
|
||||
|
||||
if (displayCount < timerCount)
|
||||
{
|
||||
EditorGUILayout.HelpBox(Utility.Text.Format("Showing first {0} timers of {1}.", displayCount, timerCount), MessageType.Info);
|
||||
}
|
||||
|
||||
for (int i = 0; i < displayCount; i++)
|
||||
{
|
||||
TimerDebugInfo timer = _timerBuffer[i];
|
||||
string label = Utility.Text.Format(
|
||||
"ID {0} | {1} | {2} | {3}",
|
||||
timer.TimerId,
|
||||
timer.IsLoop ? "Loop" : "Once",
|
||||
timer.IsUnscaled ? "Unscaled" : "Scaled",
|
||||
timer.IsRunning ? "Running" : "Paused");
|
||||
|
||||
string value = Utility.Text.Format(
|
||||
"Left {0:F2}s | Duration {1:F2}s",
|
||||
timer.LeftTime,
|
||||
timer.Duration);
|
||||
|
||||
EditorGUILayout.LabelField(label, value);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void DrawLeakDetection(ITimerServiceDebugView debugView, int activeCount)
|
||||
{
|
||||
if (activeCount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureLeakBuffer(activeCount);
|
||||
int staleCount = debugView.GetStaleOneShotTimers(_leakBuffer);
|
||||
if (staleCount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField(Utility.Text.Format("Stale One-Shot Timers ({0})", staleCount), EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox("Non-loop timers older than 5 minutes. This may indicate long-delay tasks or paused timers.", MessageType.Warning);
|
||||
|
||||
for (int i = 0; i < staleCount; i++)
|
||||
{
|
||||
TimerDebugInfo staleTimer = _leakBuffer[i];
|
||||
EditorGUILayout.LabelField(
|
||||
Utility.Text.Format("ID {0}", staleTimer.TimerId),
|
||||
Utility.Text.Format("Created {0:F1}s ago", staleTimer.CreationTime));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void EnsureTimerBuffer(int count)
|
||||
{
|
||||
if (_timerBuffer == null || _timerBuffer.Length < count)
|
||||
{
|
||||
_timerBuffer = new TimerDebugInfo[count];
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void EnsureLeakBuffer(int count)
|
||||
{
|
||||
if (_leakBuffer == null || _leakBuffer.Length < count)
|
||||
{
|
||||
_leakBuffer = new TimerDebugInfo[count];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Editor/Timer/TimerComponentInspector.cs.meta
Normal file
11
Editor/Timer/TimerComponentInspector.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02aa1426c358e87479136bd0f17f1f1c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,6 +1,4 @@
|
||||
#if ZSTRING_SUPPORT
|
||||
using Cysharp.Text;
|
||||
#endif
|
||||
using Cysharp.Text;
|
||||
|
||||
namespace AlicizaX
|
||||
{
|
||||
@ -21,11 +19,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg);
|
||||
#else
|
||||
return string.Format(format, arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -43,11 +38,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -67,11 +59,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -93,11 +82,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -121,11 +107,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -151,11 +134,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -183,11 +163,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -217,11 +194,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -253,11 +227,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -291,11 +262,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -331,11 +299,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -373,11 +338,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -417,11 +379,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -463,11 +422,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -511,11 +467,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -561,11 +514,8 @@ namespace AlicizaX
|
||||
{
|
||||
throw new GameFrameworkException("Format is invalid.");
|
||||
}
|
||||
#if ZSTRING_SUPPORT
|
||||
|
||||
return ZString.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16);
|
||||
#else
|
||||
return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,11 +21,6 @@
|
||||
"name": "com.alicizax.unity.animationflow",
|
||||
"expression": "",
|
||||
"define": "ALICIZAX_UI_ANIMATION_SUPPORT"
|
||||
},
|
||||
{
|
||||
"name": "com.alicizax.unity.cysharp.zstring",
|
||||
"expression": "2.3.0",
|
||||
"define": "ZSTRING_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
|
||||
3
Runtime/AssemblyInfo.cs
Normal file
3
Runtime/AssemblyInfo.cs
Normal file
@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("AlicizaX.Framework.Editor")]
|
||||
11
Runtime/AssemblyInfo.cs.meta
Normal file
11
Runtime/AssemblyInfo.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc79b52770c12304bbdd80020433741e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -25,6 +25,8 @@ namespace AlicizaX.Audio.Runtime
|
||||
private ulong _handle;
|
||||
private float _baseVolume;
|
||||
private float _pitch;
|
||||
private float _fadeInTimer;
|
||||
private float _fadeInDuration;
|
||||
private float _fadeTimer;
|
||||
private float _fadeDuration;
|
||||
private float _startedAt;
|
||||
@ -37,7 +39,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
internal ulong Handle => _handle;
|
||||
internal int Generation => _generation;
|
||||
internal bool IsFree => _state == AudioAgentRuntimeState.Free;
|
||||
internal bool IsPlayingState => _state == AudioAgentRuntimeState.Playing || _state == AudioAgentRuntimeState.Loading || _state == AudioAgentRuntimeState.Paused || _state == AudioAgentRuntimeState.FadingOut;
|
||||
internal bool IsPlayingState => _state == AudioAgentRuntimeState.Playing || _state == AudioAgentRuntimeState.Loading || _state == AudioAgentRuntimeState.Paused || _state == AudioAgentRuntimeState.FadingIn || _state == AudioAgentRuntimeState.FadingOut;
|
||||
internal float StartedAt => _startedAt;
|
||||
|
||||
internal void Initialize(AudioService service, AudioCategory category, int index, int globalIndex, AudioSourceObject sourceObject)
|
||||
@ -67,6 +69,8 @@ namespace AlicizaX.Audio.Runtime
|
||||
_startedAt = Time.realtimeSinceStartup;
|
||||
_baseVolume = Mathf.Clamp01(request.Volume);
|
||||
_pitch = request.Pitch <= 0f ? 1f : request.Pitch;
|
||||
_fadeInDuration = request.FadeInSeconds > 0f ? request.FadeInSeconds : 0f;
|
||||
_fadeInTimer = 0f;
|
||||
_fadeDuration = request.FadeOutSeconds > 0f ? request.FadeOutSeconds : DefaultFadeOutSeconds;
|
||||
_loop = request.Loop;
|
||||
_spatial = request.Spatial || request.FollowTarget != null || request.UseWorldPosition;
|
||||
@ -169,6 +173,22 @@ namespace AlicizaX.Audio.Runtime
|
||||
UpdateFollowTarget();
|
||||
UpdateOcclusion();
|
||||
|
||||
if (_state == AudioAgentRuntimeState.FadingIn)
|
||||
{
|
||||
_fadeInTimer += deltaTime;
|
||||
if (_fadeInTimer >= _fadeInDuration)
|
||||
{
|
||||
_state = AudioAgentRuntimeState.Playing;
|
||||
ApplyRuntimeVolume(1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
float scale = _fadeInTimer / Mathf.Max(_fadeInDuration, MinFadeOutSeconds);
|
||||
ApplyRuntimeVolume(scale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_state == AudioAgentRuntimeState.Playing)
|
||||
{
|
||||
if (!_loop && _source != null && !_source.isPlaying)
|
||||
@ -252,9 +272,20 @@ namespace AlicizaX.Audio.Runtime
|
||||
|
||||
_source.clip = clip;
|
||||
_source.loop = _loop;
|
||||
ApplyRuntimeVolume(1f);
|
||||
|
||||
if (_fadeInDuration > 0f)
|
||||
{
|
||||
_fadeInTimer = 0f;
|
||||
_state = AudioAgentRuntimeState.FadingIn;
|
||||
ApplyRuntimeVolume(0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = AudioAgentRuntimeState.Playing;
|
||||
ApplyRuntimeVolume(1f);
|
||||
}
|
||||
|
||||
_source.Play();
|
||||
_state = AudioAgentRuntimeState.Playing;
|
||||
}
|
||||
|
||||
private void StopImmediate(bool notifyCategory)
|
||||
@ -313,6 +344,8 @@ namespace AlicizaX.Audio.Runtime
|
||||
_handle = 0;
|
||||
_baseVolume = 1f;
|
||||
_pitch = 1f;
|
||||
_fadeInTimer = 0f;
|
||||
_fadeInDuration = 0f;
|
||||
_fadeTimer = 0f;
|
||||
_fadeDuration = 0f;
|
||||
_startedAt = 0f;
|
||||
|
||||
@ -6,6 +6,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
Loading = 1,
|
||||
Playing = 2,
|
||||
Paused = 3,
|
||||
FadingOut = 4
|
||||
FadingIn = 4,
|
||||
FadingOut = 5
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
using Cysharp.Text;
|
||||
|
||||
namespace AlicizaX.Audio.Runtime
|
||||
{
|
||||
@ -51,7 +52,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
_enabled = !config.Mute;
|
||||
|
||||
MixerGroup = ResolveMixerGroup(audioMixer, config);
|
||||
InstanceRoot = new GameObject("Audio Category - " + Type).transform;
|
||||
InstanceRoot = new GameObject(ZString.Concat("Audio Category - ", Type)).transform;
|
||||
InstanceRoot.SetParent(service.InstanceRoot, false);
|
||||
|
||||
int capacity = config.AgentHelperCount;
|
||||
@ -321,7 +322,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
|
||||
private static AudioMixerGroup ResolveMixerGroup(AudioMixer audioMixer, AudioGroupConfig config)
|
||||
{
|
||||
AudioMixerGroup[] groups = audioMixer.FindMatchingGroups("Master/" + config.AudioType);
|
||||
AudioMixerGroup[] groups = audioMixer.FindMatchingGroups(ZString.Concat("Master/", config.AudioType));
|
||||
if (groups != null && groups.Length > 0)
|
||||
{
|
||||
return groups[0];
|
||||
|
||||
@ -9,7 +9,6 @@ namespace AlicizaX.Audio.Runtime
|
||||
public sealed class AudioComponent : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private AudioMixer m_AudioMixer;
|
||||
[SerializeField] private Transform m_InstanceRoot;
|
||||
[SerializeField] private AudioListener m_AudioListener;
|
||||
[SerializeField] private AudioGroupConfigCollection m_AudioGroupConfigs;
|
||||
|
||||
@ -22,10 +21,13 @@ namespace AlicizaX.Audio.Runtime
|
||||
|
||||
private void Start()
|
||||
{
|
||||
EnsureInstanceRoot();
|
||||
EnsureAudioMixer();
|
||||
if (m_AudioMixer == null)
|
||||
{
|
||||
throw new GameFrameworkException("AudioMixer is not assigned. Please assign an AudioMixer in the inspector.");
|
||||
}
|
||||
|
||||
AudioGroupConfig[] configs = m_AudioGroupConfigs != null ? m_AudioGroupConfigs.GroupConfigs : null;
|
||||
_audioService.Initialize(configs, m_InstanceRoot, m_AudioMixer);
|
||||
_audioService.Initialize(configs, transform, m_AudioMixer);
|
||||
if (m_AudioListener != null)
|
||||
{
|
||||
_audioService.RegisterListener(m_AudioListener);
|
||||
@ -47,26 +49,5 @@ namespace AlicizaX.Audio.Runtime
|
||||
_audioService.UnregisterListener(m_AudioListener);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureInstanceRoot()
|
||||
{
|
||||
if (m_InstanceRoot != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_InstanceRoot = new GameObject("[AudioService Instances]").transform;
|
||||
m_InstanceRoot.SetParent(transform, false);
|
||||
m_InstanceRoot.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
private void EnsureAudioMixer()
|
||||
{
|
||||
if (m_AudioMixer == null)
|
||||
{
|
||||
m_AudioMixer = Resources.Load<AudioMixer>("AudioMixer");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
public float MaxDistance;
|
||||
public AudioRolloffMode RolloffMode;
|
||||
public bool OverrideSpatialSettings;
|
||||
public float FadeInSeconds;
|
||||
public float FadeOutSeconds;
|
||||
|
||||
public AudioPlayRequest()
|
||||
@ -157,6 +158,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
MaxDistance = 500f;
|
||||
RolloffMode = AudioRolloffMode.Logarithmic;
|
||||
OverrideSpatialSettings = false;
|
||||
FadeInSeconds = 0f;
|
||||
FadeOutSeconds = 0.15f;
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ using AlicizaX.Resource.Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
using YooAsset;
|
||||
using Cysharp.Text;
|
||||
|
||||
namespace AlicizaX.Audio.Runtime
|
||||
{
|
||||
@ -31,6 +32,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
private readonly bool[] _categoryEnables = new bool[(int)AudioType.Max];
|
||||
private readonly Dictionary<string, AudioClipCacheEntry> _clipCache = new Dictionary<string, AudioClipCacheEntry>(DefaultCacheCapacity, StringComparer.Ordinal);
|
||||
private readonly AudioSourceObject[][] _sourceObjects = new AudioSourceObject[(int)AudioType.Max][];
|
||||
private readonly Dictionary<AudioType, AudioGroupConfig> _configMap = new Dictionary<AudioType, AudioGroupConfig>((int)AudioType.Max);
|
||||
|
||||
private IResourceService _resourceService;
|
||||
private IObjectPool<AudioSourceObject> _sourcePool;
|
||||
@ -109,18 +111,41 @@ namespace AlicizaX.Audio.Runtime
|
||||
{
|
||||
Shutdown(false);
|
||||
|
||||
_resourceService = AppServices.Require<IResourceService>();
|
||||
IObjectPoolService objectPoolService = AppServices.Require<IObjectPoolService>();
|
||||
_sourcePool = objectPoolService.HasObjectPool<AudioSourceObject>(SourcePoolName)
|
||||
? objectPoolService.GetObjectPool<AudioSourceObject>(SourcePoolName)
|
||||
: objectPoolService.CreatePool<AudioSourceObject>(new ObjectPoolCreateOptions(SourcePoolName, false, 10f, int.MaxValue, float.MaxValue, 10));
|
||||
|
||||
if (audioGroupConfigs == null || audioGroupConfigs.Length == 0)
|
||||
{
|
||||
throw new GameFrameworkException("AudioGroupConfig[] is invalid.");
|
||||
}
|
||||
|
||||
_configs = audioGroupConfigs;
|
||||
BuildConfigMap();
|
||||
|
||||
InitializeObjectPools();
|
||||
InitializeInstanceRoot(instanceRoot);
|
||||
InitializeAudioMixer(audioMixer);
|
||||
|
||||
if (_unityAudioDisabled)
|
||||
{
|
||||
_initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeHandleSystem();
|
||||
InitializeCategories();
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private void InitializeObjectPools()
|
||||
{
|
||||
_resourceService = AppServices.Require<IResourceService>();
|
||||
IObjectPoolService objectPoolService = AppServices.Require<IObjectPoolService>();
|
||||
_sourcePool = objectPoolService.HasObjectPool<AudioSourceObject>(SourcePoolName)
|
||||
? objectPoolService.GetObjectPool<AudioSourceObject>(SourcePoolName)
|
||||
: objectPoolService.CreatePool<AudioSourceObject>(new ObjectPoolCreateOptions(SourcePoolName, false, 10f, int.MaxValue, float.MaxValue, 10));
|
||||
}
|
||||
|
||||
private void InitializeInstanceRoot(Transform instanceRoot)
|
||||
{
|
||||
if (instanceRoot != null)
|
||||
{
|
||||
_instanceRoot = instanceRoot;
|
||||
@ -138,20 +163,25 @@ namespace AlicizaX.Audio.Runtime
|
||||
{
|
||||
UnityEngine.Object.DontDestroyOnLoad(_instanceRoot.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeAudioMixer(AudioMixer audioMixer)
|
||||
{
|
||||
_unityAudioDisabled = IsUnityAudioDisabled();
|
||||
if (_unityAudioDisabled)
|
||||
{
|
||||
_initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_audioMixer = audioMixer != null ? audioMixer : Resources.Load<AudioMixer>("AudioMixer");
|
||||
_audioMixer = audioMixer;
|
||||
if (_audioMixer == null)
|
||||
{
|
||||
throw new GameFrameworkException("AudioMixer is invalid.");
|
||||
throw new GameFrameworkException("AudioMixer is invalid. Please provide a valid AudioMixer.");
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeHandleSystem()
|
||||
{
|
||||
int totalAgentCount = 0;
|
||||
for (int i = 0; i < (int)AudioType.Max; i++)
|
||||
{
|
||||
@ -169,7 +199,10 @@ namespace AlicizaX.Audio.Runtime
|
||||
MemoryPool.Add<AudioPlayRequest>(totalAgentCount);
|
||||
MemoryPool.Add<AudioLoadRequest>(totalAgentCount);
|
||||
MemoryPool.Add<AudioClipCacheEntry>(_clipCacheCapacity);
|
||||
}
|
||||
|
||||
private void InitializeCategories()
|
||||
{
|
||||
int globalIndexOffset = 0;
|
||||
for (int i = 0; i < (int)AudioType.Max; i++)
|
||||
{
|
||||
@ -186,8 +219,6 @@ namespace AlicizaX.Audio.Runtime
|
||||
globalIndexOffset += config.AgentHelperCount;
|
||||
ApplyMixerVolume(config, _categoryVolumes[i], _categoryEnables[i]);
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
@ -439,12 +470,17 @@ namespace AlicizaX.Audio.Runtime
|
||||
}
|
||||
|
||||
public void ClearCache()
|
||||
{
|
||||
ClearCache(false);
|
||||
}
|
||||
|
||||
private void ClearCache(bool force)
|
||||
{
|
||||
AudioClipCacheEntry entry = _allHead;
|
||||
while (entry != null)
|
||||
{
|
||||
AudioClipCacheEntry next = entry.AllNext;
|
||||
if (entry.RefCount <= 0 && !entry.Loading && entry.PendingHead == null)
|
||||
if (force || (entry.RefCount <= 0 && !entry.Loading && entry.PendingHead == null))
|
||||
{
|
||||
RemoveClipEntry(entry);
|
||||
}
|
||||
@ -1073,7 +1109,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
|
||||
private static string BuildSourceName(int typeIndex, int index)
|
||||
{
|
||||
return "AudioSource_" + typeIndex + "_" + index;
|
||||
return ZString.Concat("AudioSource_", typeIndex, "_", index);
|
||||
}
|
||||
|
||||
private AudioGroupConfig GetConfig(AudioType type)
|
||||
@ -1087,23 +1123,27 @@ namespace AlicizaX.Audio.Runtime
|
||||
return FindConfig(type);
|
||||
}
|
||||
|
||||
private AudioGroupConfig FindConfig(AudioType type)
|
||||
private void BuildConfigMap()
|
||||
{
|
||||
_configMap.Clear();
|
||||
if (_configs == null)
|
||||
{
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _configs.Length; i++)
|
||||
{
|
||||
AudioGroupConfig config = _configs[i];
|
||||
if (config != null && config.AudioType == type)
|
||||
if (config != null)
|
||||
{
|
||||
return config;
|
||||
_configMap[config.AudioType] = config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
private AudioGroupConfig FindConfig(AudioType type)
|
||||
{
|
||||
return _configMap.TryGetValue(type, out AudioGroupConfig config) ? config : null;
|
||||
}
|
||||
|
||||
private int CountActiveAgents()
|
||||
@ -1143,7 +1183,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
ClearCache();
|
||||
ClearCache(true);
|
||||
if (_sourcePool != null)
|
||||
{
|
||||
_sourcePool.ReleaseAllUnused();
|
||||
@ -1153,6 +1193,7 @@ namespace AlicizaX.Audio.Runtime
|
||||
Array.Clear(_handleGenerations, 0, _handleGenerations.Length);
|
||||
_handleAgents = Array.Empty<AudioAgent>();
|
||||
_handleGenerations = Array.Empty<uint>();
|
||||
_configMap.Clear();
|
||||
_resourceService = null;
|
||||
_sourcePool = null;
|
||||
_audioMixer = null;
|
||||
|
||||
@ -61,6 +61,25 @@ AudioMixerGroupController:
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!243 &-6728185375074428080
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Ambient - 2
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: df8234ed398782540a4972841dfd6079
|
||||
m_Children: []
|
||||
m_Volume: 9d25aae74848d51418de553067dd0f0b
|
||||
m_Pitch: 2018eb0e2888cff44bf523ce3d06fd0b
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: -2815600738436590526}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!243 &-6280614258348125054
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -80,6 +99,25 @@ AudioMixerGroupController:
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!243 &-5751393387862637061
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Ambient - 1
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: 221f1da294156a3418168c39f16ae139
|
||||
m_Children: []
|
||||
m_Volume: 3a4c4abef80a7d74090c4558f2efbe8c
|
||||
m_Pitch: bade8e01a57417d49bccd39245648de8
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: 588078238856344238}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!244 &-4958177229083455073
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
@ -94,6 +132,25 @@ AudioMixerEffectController:
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!243 &-4470511876276122591
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Ambient - 3
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: 62ab3b1c1e1517f4892acd6bbf63325e
|
||||
m_Children: []
|
||||
m_Volume: ae513375e8726984d88a822dcc805a47
|
||||
m_Pitch: c670d6f9426d69c439bed5c1581cf095
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: 4372151859782775079}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!243 &-4372808504093502661
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -186,6 +243,43 @@ AudioMixerGroupController:
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!243 &-3339031547535134654
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Ambient
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: eea06a873d29c174d9b93c8a87f28f29
|
||||
m_Children:
|
||||
- {fileID: -1635570523224726303}
|
||||
- {fileID: -5751393387862637061}
|
||||
- {fileID: -6728185375074428080}
|
||||
- {fileID: -4470511876276122591}
|
||||
m_Volume: 41dabee1ece434b46b30b1bf6008f4eb
|
||||
m_Pitch: fef56cb47e7fcb845ae02cd29b60365e
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: -1709768828366853691}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!244 &-2815600738436590526
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Attenuation
|
||||
m_EffectID: 89fdfdacd88dd56428258e46d756e1ea
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: c67a0995f8d7b524ba49eeeca5216f58
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!243 &-2659745067392564156
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -219,6 +313,20 @@ AudioMixerEffectController:
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!244 &-1709768828366853691
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_EffectID: 65bb23c9d872c5347a34674e11b855f2
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: eeea8e411d955da479365f63ad7834fd
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!243 &-1649243360580130678
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -238,6 +346,39 @@ AudioMixerGroupController:
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!243 &-1635570523224726303
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Ambient - 0
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: dfba3d60853b22649ac844b8e925e0f6
|
||||
m_Children: []
|
||||
m_Volume: d292610df4aee5543b1124a0f1048e76
|
||||
m_Pitch: 2d28f5f5a88e080488060323fd5d5d55
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: -1114540582412186105}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!244 &-1114540582412186105
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_EffectID: 10f22744f37e0a143adcb17b39acf14a
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: c4b8d05d2d796eb46b9288ae6451e044
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!244 &-998299258853400712
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
@ -359,6 +500,11 @@ AudioMixerController:
|
||||
- e012b6d2e0501df43a88eb6beff8ae07
|
||||
- e84c25a476798ea43a2f6de217af7dba
|
||||
- 98657376d4096a947953ee04d82830c1
|
||||
- eea06a873d29c174d9b93c8a87f28f29
|
||||
- dfba3d60853b22649ac844b8e925e0f6
|
||||
- 221f1da294156a3418168c39f16ae139
|
||||
- df8234ed398782540a4972841dfd6079
|
||||
- 62ab3b1c1e1517f4892acd6bbf63325e
|
||||
name: View
|
||||
m_CurrentViewIndex: 0
|
||||
m_TargetSnapshot: {fileID: 24500006}
|
||||
@ -376,6 +522,7 @@ AudioMixerGroupController:
|
||||
- {fileID: 7235523536312936115}
|
||||
- {fileID: 7185772616558441635}
|
||||
- {fileID: -3395020342500439107}
|
||||
- {fileID: -3339031547535134654}
|
||||
m_Volume: ba83e724007d7e9459f157db3a54a741
|
||||
m_Pitch: a2d2b77391464bb4887f0bcd3835015b
|
||||
m_Send: 00000000000000000000000000000000
|
||||
@ -448,6 +595,20 @@ AudioMixerEffectController:
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!244 &588078238856344238
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Attenuation
|
||||
m_EffectID: fe69f682bd0b54a42a947db1c2b9c800
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: ca7defaf1a72196439b28b45a8ca0dc6
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!244 &1413273517213151576
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
@ -533,6 +694,20 @@ AudioMixerGroupController:
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!244 &4372151859782775079
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Attenuation
|
||||
m_EffectID: 3519e333bc2088840ad9986fa50cde94
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: 04a4d4239cebc9348a0e8e88df14e74c
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!244 &5734415080786067514
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
|
||||
200
Runtime/Debugger/DebuggerComponent.TimerInformationWindow.cs
Normal file
200
Runtime/Debugger/DebuggerComponent.TimerInformationWindow.cs
Normal file
@ -0,0 +1,200 @@
|
||||
using AlicizaX.Timer.Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace AlicizaX.Debugger.Runtime
|
||||
{
|
||||
public sealed partial class DebuggerComponent
|
||||
{
|
||||
private sealed class TimerInformationWindow : ScrollableDebuggerWindowBase
|
||||
{
|
||||
private const int MAX_DISPLAY_COUNT = 50;
|
||||
|
||||
private struct RowView
|
||||
{
|
||||
public VisualElement Root;
|
||||
public Label Title;
|
||||
public Label Value;
|
||||
}
|
||||
|
||||
private ITimerServiceDebugView m_TimerDebugView;
|
||||
private TimerDebugInfo[] m_TimerInfos;
|
||||
private Label m_SectionTitleLabel;
|
||||
private Label m_ActiveCountLabel;
|
||||
private Label m_PoolCapacityLabel;
|
||||
private Label m_PeakCountLabel;
|
||||
private Label m_FreeCountLabel;
|
||||
private Label m_UsageLabel;
|
||||
private Label m_WarningLabel;
|
||||
private RowView m_EmptyRow;
|
||||
private readonly RowView[] m_TimerRows = new RowView[MAX_DISPLAY_COUNT];
|
||||
|
||||
public override void Initialize(params object[] args)
|
||||
{
|
||||
m_TimerDebugView = AppServices.Require<ITimerService>() as ITimerServiceDebugView;
|
||||
}
|
||||
|
||||
protected override void BuildWindow(VisualElement root)
|
||||
{
|
||||
if (m_TimerDebugView == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
root.Add(CreateActionButton("Refresh", RefreshContent, DebuggerTheme.ButtonSurfaceActive, DebuggerTheme.PrimaryText));
|
||||
|
||||
VisualElement overview = CreateSection("Timer Pool Overview", out VisualElement overviewCard);
|
||||
m_ActiveCountLabel = AddTextRow(overviewCard, "Active Timer Count").Value;
|
||||
m_PoolCapacityLabel = AddTextRow(overviewCard, "Pool Capacity").Value;
|
||||
m_PeakCountLabel = AddTextRow(overviewCard, "Peak Active Count").Value;
|
||||
m_FreeCountLabel = AddTextRow(overviewCard, "Free Count").Value;
|
||||
m_UsageLabel = AddTextRow(overviewCard, "Pool Usage").Value;
|
||||
root.Add(overview);
|
||||
|
||||
VisualElement section = CreateSection("Active Timers", out VisualElement timerCard);
|
||||
m_SectionTitleLabel = section.ElementAt(0) as Label;
|
||||
m_WarningLabel = new Label();
|
||||
m_WarningLabel.style.color = new Color(1f, 0.5f, 0f);
|
||||
m_WarningLabel.style.display = DisplayStyle.None;
|
||||
m_WarningLabel.style.marginBottom = 4f;
|
||||
timerCard.Add(m_WarningLabel);
|
||||
|
||||
m_EmptyRow = AddTextRow(timerCard, string.Empty);
|
||||
m_EmptyRow.Root.style.display = DisplayStyle.None;
|
||||
|
||||
for (int i = 0; i < MAX_DISPLAY_COUNT; i++)
|
||||
{
|
||||
m_TimerRows[i] = AddTextRow(timerCard, string.Empty);
|
||||
m_TimerRows[i].Root.style.display = DisplayStyle.None;
|
||||
}
|
||||
|
||||
root.Add(section);
|
||||
RefreshContent();
|
||||
}
|
||||
|
||||
private void RefreshContent()
|
||||
{
|
||||
if (m_TimerDebugView == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_TimerDebugView.GetStatistics(out int activeCount, out int poolCapacity, out int peakActiveCount, out int freeCount);
|
||||
float poolUsage = poolCapacity > 0 ? (float)activeCount / poolCapacity : 0f;
|
||||
|
||||
m_ActiveCountLabel.text = activeCount.ToString();
|
||||
m_PoolCapacityLabel.text = poolCapacity.ToString();
|
||||
m_PeakCountLabel.text = peakActiveCount.ToString();
|
||||
m_FreeCountLabel.text = freeCount.ToString();
|
||||
m_UsageLabel.text = Utility.Text.Format("{0:P1}", poolUsage);
|
||||
|
||||
if (activeCount <= 0)
|
||||
{
|
||||
m_SectionTitleLabel.text = "Active Timers";
|
||||
m_WarningLabel.style.display = DisplayStyle.None;
|
||||
m_EmptyRow.Root.style.display = DisplayStyle.Flex;
|
||||
m_EmptyRow.Title.text = "Status";
|
||||
m_EmptyRow.Value.text = "No active timers";
|
||||
SetTimerRowsVisible(0);
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTimerInfoBuffer(activeCount);
|
||||
int timerCount = m_TimerDebugView.GetAllTimers(m_TimerInfos);
|
||||
int displayCount = timerCount > MAX_DISPLAY_COUNT ? MAX_DISPLAY_COUNT : timerCount;
|
||||
|
||||
m_SectionTitleLabel.text = Utility.Text.Format("Active Timers ({0})", timerCount);
|
||||
m_EmptyRow.Root.style.display = DisplayStyle.None;
|
||||
|
||||
if (displayCount < timerCount)
|
||||
{
|
||||
m_WarningLabel.text = Utility.Text.Format("Showing first {0} timers of {1}.", displayCount, timerCount);
|
||||
m_WarningLabel.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_WarningLabel.style.display = DisplayStyle.None;
|
||||
}
|
||||
|
||||
for (int i = 0; i < displayCount; i++)
|
||||
{
|
||||
ref RowView row = ref m_TimerRows[i];
|
||||
TimerDebugInfo info = m_TimerInfos[i];
|
||||
row.Title.text = Utility.Text.Format("Timer #{0}", info.TimerId);
|
||||
row.Value.text = Utility.Text.Format(
|
||||
"{0} | {1} | {2} | Remaining: {3:F2}s | Duration: {4:F2}s",
|
||||
info.IsLoop ? "Loop" : "Once",
|
||||
info.IsRunning ? "Running" : "Paused",
|
||||
info.IsUnscaled ? "Unscaled" : "Scaled",
|
||||
info.LeftTime,
|
||||
info.Duration);
|
||||
row.Root.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
|
||||
SetTimerRowsVisible(displayCount);
|
||||
}
|
||||
|
||||
private void SetTimerRowsVisible(int visibleCount)
|
||||
{
|
||||
for (int i = 0; i < MAX_DISPLAY_COUNT; i++)
|
||||
{
|
||||
m_TimerRows[i].Root.style.display = i < visibleCount ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
|
||||
private RowView AddTextRow(VisualElement parent, string title)
|
||||
{
|
||||
float scale = DebuggerComponent.Instance != null ? DebuggerComponent.Instance.GetUiScale() : 1f;
|
||||
VisualElement row = new VisualElement();
|
||||
row.style.flexDirection = FlexDirection.Row;
|
||||
row.style.alignItems = Align.Center;
|
||||
row.style.minHeight = 36f * scale;
|
||||
row.style.marginBottom = 4f * scale;
|
||||
|
||||
Label titleLabel = new Label(title);
|
||||
titleLabel.style.minWidth = 280f * scale;
|
||||
titleLabel.style.maxWidth = 280f * scale;
|
||||
titleLabel.style.color = DebuggerTheme.SecondaryText;
|
||||
titleLabel.style.fontSize = 18f * scale;
|
||||
titleLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
titleLabel.style.flexShrink = 0f;
|
||||
titleLabel.style.whiteSpace = WhiteSpace.Normal;
|
||||
|
||||
Label valueLabel = new Label();
|
||||
valueLabel.style.flexGrow = 1f;
|
||||
valueLabel.style.color = DebuggerTheme.PrimaryText;
|
||||
valueLabel.style.fontSize = 18f * scale;
|
||||
valueLabel.style.whiteSpace = WhiteSpace.Normal;
|
||||
|
||||
row.Add(titleLabel);
|
||||
row.Add(valueLabel);
|
||||
parent.Add(row);
|
||||
|
||||
RowView view;
|
||||
view.Root = row;
|
||||
view.Title = titleLabel;
|
||||
view.Value = valueLabel;
|
||||
return view;
|
||||
}
|
||||
|
||||
private int EnsureTimerInfoBuffer(int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
{
|
||||
if (m_TimerInfos == null || m_TimerInfos.Length == 0)
|
||||
{
|
||||
m_TimerInfos = new TimerDebugInfo[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_TimerInfos == null || m_TimerInfos.Length < count)
|
||||
{
|
||||
m_TimerInfos = new TimerDebugInfo[count];
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8eac2550d41d14641b41a5c5523c4fde
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -93,6 +93,7 @@ namespace AlicizaX.Debugger.Runtime
|
||||
private ObjectPoolInformationWindow m_ObjectPoolInformationWindow = new ObjectPoolInformationWindow();
|
||||
private ReferencePoolInformationWindow m_ReferencePoolInformationWindow = new ReferencePoolInformationWindow();
|
||||
private AudioInformationWindow m_AudioInformationWindow = new AudioInformationWindow();
|
||||
private TimerInformationWindow m_TimerInformationWindow = new TimerInformationWindow();
|
||||
private SettingsWindow m_SettingsWindow = new SettingsWindow();
|
||||
private FpsCounter m_FpsCounter;
|
||||
|
||||
@ -502,6 +503,7 @@ namespace AlicizaX.Debugger.Runtime
|
||||
RegisterDebuggerWindow("Profiler/Object Pool", m_ObjectPoolInformationWindow);
|
||||
RegisterDebuggerWindow("Profiler/Reference Pool", m_ReferencePoolInformationWindow);
|
||||
RegisterDebuggerWindow("Profiler/Audio", m_AudioInformationWindow);
|
||||
RegisterDebuggerWindow("Profiler/Timer", m_TimerInformationWindow);
|
||||
RegisterDebuggerWindow("Other/Settings", m_SettingsWindow);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ using AlicizaX.Localization.Runtime;
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX.Resource.Runtime;
|
||||
using AlicizaX.Scene.Runtime;
|
||||
using AlicizaX.Timer.Runtime;
|
||||
using AlicizaX.UI.Runtime;
|
||||
|
||||
public static partial class GameApp
|
||||
|
||||
@ -1,19 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace AlicizaX
|
||||
namespace AlicizaX.Timer.Runtime
|
||||
{
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public interface ITimerService : IService
|
||||
{
|
||||
int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args);
|
||||
int AddTimer(TimerHandlerNoArgs callback, float time, bool isLoop = false, bool isUnscaled = false);
|
||||
int AddTimer<T>(Action<T> callback, T arg, float time, bool isLoop = false, bool isUnscaled = false);
|
||||
int AddTimer<T>(Action<T> callback, T arg, float time, bool isLoop = false, bool isUnscaled = false) where T : class;
|
||||
void Stop(int timerId);
|
||||
void Resume(int timerId);
|
||||
bool IsRunning(int timerId);
|
||||
float GetLeftTime(int timerId);
|
||||
void Restart(int timerId);
|
||||
void RemoveTimer(int timerId);
|
||||
void RemoveAllTimer();
|
||||
}
|
||||
}
|
||||
|
||||
27
Runtime/Timer/ITimerServiceDebugView.cs
Normal file
27
Runtime/Timer/ITimerServiceDebugView.cs
Normal file
@ -0,0 +1,27 @@
|
||||
namespace AlicizaX.Timer.Runtime
|
||||
{
|
||||
internal struct TimerDebugInfo
|
||||
{
|
||||
public int TimerId;
|
||||
public float LeftTime;
|
||||
public float Duration;
|
||||
public bool IsLoop;
|
||||
public bool IsRunning;
|
||||
public bool IsUnscaled;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public float CreationTime;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal interface ITimerServiceDebugView
|
||||
{
|
||||
int GetAllTimers(TimerDebugInfo[] results);
|
||||
|
||||
void GetStatistics(out int activeCount, out int poolCapacity, out int peakActiveCount, out int freeCount);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
int GetStaleOneShotTimers(TimerDebugInfo[] results);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Runtime/Timer/ITimerServiceDebugView.cs.meta
Normal file
11
Runtime/Timer/ITimerServiceDebugView.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b7cf36ada40b944f8c506e3cd8ddd12
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -10,6 +10,11 @@ namespace AlicizaX.Timer.Runtime
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
if (AppServices.TryGet<ITimerService>(out _))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AppServices.RegisterApp(new TimerService());
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 205d0803930745d7825f89aa604530a5
|
||||
timeCreated: 1741683842
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX;
|
||||
using AlicizaX.Timer.Runtime;
|
||||
|
||||
namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
@ -46,8 +47,7 @@ namespace AlicizaX.UI.Runtime
|
||||
uiMetadata,
|
||||
uiMetadata.MetaInfo.CacheTime,
|
||||
isLoop: false,
|
||||
isUnscaled: true
|
||||
);
|
||||
isUnscaled: true);
|
||||
|
||||
if (timerId <= 0)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user