canto/Assets/Scripts/SOAP/ReactiveInputAction.cs
2025-07-14 22:22:25 -04:00

105 lines
3 KiB
C#

using System;
using UnityEngine;
using UnityEngine.InputSystem;
namespace KitsuneCafe.SOAP
{
public class ReactiveInputAction<T> : ScriptableObject where T : struct
{
[SerializeField]
private ReactiveEvent<T> started;
[SerializeField]
private ReactiveEvent<T> performed;
[SerializeField]
private ReactiveEvent<T> canceled;
[SerializeField]
private ReactiveEvent<T> waiting;
[SerializeField]
private ReactiveEvent<T> disabled;
[SerializeField]
private ReactiveValue<T> reactiveValue;
[SerializeField]
private ReactiveValue<bool> valueAsButton;
public virtual void Handle(InputAction.CallbackContext context)
{
T value = context.ReadValue<T>();
Raise(context.phase, value);
UpdateValue(reactiveValue, value);
UpdateValue(valueAsButton, context);
}
protected void UpdateValue(ReactiveValue<T> property, T value)
{
if (property != null)
{
property.Value = value;
}
}
protected void UpdateValue(ReactiveValue<T> property, InputAction.CallbackContext context)
{
if (property != null)
{
property.Value = context.ReadValue<T>();
}
}
protected void UpdateValue(ReactiveValue<bool> property, InputAction.CallbackContext context)
{
if (property != null)
{
property.Value = context.ReadValueAsButton();
}
}
public virtual void UpdateValue(InputAction.CallbackContext context)
{
UpdateValue(reactiveValue, context.ReadValue<T>());
UpdateValue(valueAsButton, context);
}
protected virtual void Raise(InputActionPhase phase, T value)
{
switch (phase)
{
case InputActionPhase.Started:
TryRaise(started, value);
break;
case InputActionPhase.Performed:
TryRaise(performed, value);
break;
case InputActionPhase.Canceled:
TryRaise(canceled, value);
break;
case InputActionPhase.Waiting:
TryRaise(waiting, value);
break;
case InputActionPhase.Disabled:
TryRaise(disabled, value);
break;
default:
throw new ArgumentException($"{phase} is not a valid InputActionPhase");
}
}
public virtual void Raise(InputAction.CallbackContext context)
{
Raise(context.phase, context.ReadValue<T>());
}
private void TryRaise(ReactiveEvent<T> evt, T value)
{
if (evt != null)
{
evt.Raise(value);
}
}
}
}