[FEATURE] Allow listening to AtomReference even with Value or Const usage
lgarczyn opened this issue · comments
Is your feature request related to a problem? Please describe.
The choice between using an AtomReference and AtomEventReference is always a bit difficult.
Usually it's something like
Reference | EventReference | |
---|---|---|
Reading | Has a garanteed value | Doesn't have a garanteed value (but can replay previous one) |
Reacting | Can be listened to through GetEvent/GetOrCreateEvent (except on Value/Const usage) | Made to be listened to |
I've started to think of Variables simply as Events with base values. No data can guarantee that it will only has either the "reading a value when you need it" use-case or the "waiting for a value to change" use-case.
It can simply state "do I have a default value or not".
But right now if I want an reference that guarantees a default value AND can be listened to, I have a problem.
(current example, I want to set fmod parameter using an AtomReference. I need to update the parameter when it changes, but I also want to read that value when a new audio event starts)
Describe the solution you'd like
If this approach makes sense to you, then you should be able to get an event for any type of variable.
In the case of a "Value" usage, then it should do two things:
- replay its value when subscribed to
- if the user modified the value from the inspector, emit a value
The API would be harmonized, simply implementing IGetOrCreateEvent for AtomReference
This would cover the "gap" where you need to both read a variable and react to it.
Describe alternatives you've considered
static E GetFakeEvent<T, E>(T replayValue)
where E : AtomEvent<T>
{
E output = ScriptableObject.CreateInstance<E>();
// Add replay value to buffer
output.Raise(replayValue);
return output;
}
public static E1 GetOrCreateEvent<T, P, C, TV, E1, E2, F, TVi>(this AtomReference<T, P, C, TV, E1, E2, F, TVi> reference)
where P : struct, IPair<T>
where C : AtomBaseVariable<T>
where TV : AtomVariable<T, P, E1, E2, F>
where E1 : AtomEvent<T>
where E2 : AtomEvent<P>
where F : AtomFunction<T, T>
where TVi : AtomVariableInstancer<TV, P, T, E1, E2, F>
{
switch (reference.Usage)
{
case AtomReferenceUsage.VALUE :
case AtomReferenceUsage.CONSTANT : return GetFakeEvent<T, E1>(reference.Value);
default: return reference.GetEvent<E1>();
}
}
This does everything except the inspector stuff, and actually implementing the IGetOrCreateEvent interface.
This could only be done by extending or modifying AtomBaseReference (for example with an OnValidate function).
Additional context
Big problem with this idea, is if people expect that directly setting the value will trigger those events.
I'm not exactly sure if it shouldn't trigger them. It could be a lightweight alternative to instancers, but I don't feel comfortable with it.
We could have warning logs if someone modifies those values at runtime after fake events have been created, but that's obviously simply a band-aid.