using Sandbox; using Sandbox.Audio; using System.Threading; using System.Threading.Tasks; namespace Sandbox; public sealed class DSPReverb : Component, Component.ITriggerListener { [Property] public MixerHandle TargetMixer { get; set; } [Property] public DspPresetHandle Preset { get; set; } [Property] [Range( 0f, 10f, 0.1f )] public float FadeDuration { get; set; } = 1f; [Property] public BBox Bounds { get; set; } = new BBox( Vector3.One * -100f, Vector3.One * 100f ); private DspProcessor _processor; private BoxCollider _triggerCollider; private CancellationTokenSource _cts; protected override void OnAwake() { base.OnAwake(); _triggerCollider = Components.Create(); _triggerCollider.IsTrigger = true; _triggerCollider.Static = true; _triggerCollider.Scale = Bounds.Size; _triggerCollider.Center = Bounds.Center; } public void OnTriggerEnter( Collider other ) { if ( other.Components.TryGet( out Dedugan dedugan ) ) { if ( dedugan.Connection == Dedugan.Local.Connection ) { _cts?.Cancel(); _cts = new CancellationTokenSource(); if ( _processor != null ) { TargetMixer.Get().RemoveProcessor( _processor ); } _processor = new DspProcessor( Preset.Name ); _processor.Mix = 0f; TargetMixer.Get().AddProcessor( _processor ); _processor.Mix = 1f; // _ = UpdateMixAsync(1f); } } } private async Task UpdateMixAsync( float targetMix ) { float startMix = _processor.Mix; float elapsed = FadeDuration * ((targetMix == 0f || startMix == 0f) ? 0f : Math.Min( startMix / targetMix, 1f )); float lastTime = Time.Now; while ( elapsed < FadeDuration && !_cts.IsCancellationRequested ) { await Task.FixedUpdate(); float delta = Time.Now - lastTime; elapsed += delta; float t = Math.Clamp( elapsed / FadeDuration, 0f, 1f ); _processor.Mix = Math.Clamp( startMix + (targetMix - startMix) * t, 0f, 1f ); lastTime = Time.Now; } if ( !_cts.IsCancellationRequested ) { _processor.Mix = targetMix; } } public void OnTriggerExit( Collider other ) { if ( other.Components.TryGet( out Dedugan dedugan ) ) { if ( dedugan.Connection == Dedugan.Local.Connection ) { _cts?.Cancel(); _cts = new CancellationTokenSource(); _processor.Mix = 0f; } } // _ = UpdateMixAsync(0f).ContinueWith( (_) => // { // if (_processor == null) return; // // TargetMixer.Get().RemoveProcessor(_processor); // _processor = null; // } ); } protected override void DrawGizmos() { base.DrawGizmos(); Gizmo.Draw.Color = Color.Green; Gizmo.Draw.LineBBox( Bounds ); } }