I was thinking about the new Local Storage plugin and how it's a little tricker to use with the new asynchronous style of access. Previously with WebStorage you could just directly retrieve a value in an expression:
This is really easy to use, but has the disadvantage of being synchronous, i.e. it pauses and waits for "MyValue" to be read from storage. If the system is busy or it's a large value, this could take say 100ms, and the game freezes for this time (jank).
Local Storage solves this with asynchronous storage. You use the 'Get item' action, which then triggers 'On item get':
Now if it takes 100ms to read, it continues running the game while reading from storage in parallel, and when finished it triggers 'On item get'. The new problem is now the reading logic is in a trigger event. This event could be far away from the action that started it (e.g. in a different sheet). It could also be inconvenient if there are multiple 'On item "MyValue" get' triggers for different purposes, and they all trigger at the same time based on this one action. This gets more complicated if you want to do something else async afterwards, e.g. set a value, which involves more triggers.
This can be solved with good organisation, but it would be nice if we could have events that are both async and as easy as the sync version. In Javascript "Promises" go a long way to help making this easy, so I was thinking of a similar type of feature for the event system - a "Then" condition, which triggers whenever the previous event's asynchronous action finishes (mockup):
The "Then" trigger is tightly coupled with the previous event, in the same way the "Else" event is based on the event directly preceding it rather than working by itself (and that also means there are valid and invalid places to put it). It works the same as the previous async example, but:
- you didn't have to find the right trigger to use
- you didn't have to type in "MyValue" again for the trigger, it knows it's triggering for that value from the previous event
- it guarantees the thing to be done afterwards is in the next event, not somewhere far away, keeping events tidy
- it only fires the one "Then" trigger, not every trigger of that kind in the event sheet, making it easier to use if the value is loaded for different reasons in different places
- this might end up being a C3 feature, not sure it would make C2
I think to make it clear the asynchronous action needs to be clearly marked - I just scrawled in a red asterisk as a placeholder representation.
This kind of asynchronous "Then" event could be applied to all sorts of objects which already implement asynchronous features:
- AJAX "Request URL" could be followed by "then" which is fired when the response is received, and would mean you don't need to worry about getting tags right
- "Request user media", "Request fullscreen", "Request location" or other user-prompting actions can fire "then" after they are approved/get data
- Pathfinding could fire "then" after the path is found
- third party plugins could integrate with the "then" trigger
- anything we add in future could more easily use asynchronous actions, making it easier to add parallel features that make use of multiple cores
A few other thoughts:
- the "Then" condition would have the caveat that you can only have a single async action in the previous event. If there were two, it wouldn't know which to fire "then" for. So in that case you'd probably have to go back to using the existing trigger system.
- "Then" triggers could be chained. So the "Then" event could contain another async action, and be followed by another "Then" trigger, making a clear sequence of actions which run in parallel.
- Async actions can fail, e.g. AJAX "On error", Pathfinding "Path not found" etc. I guess there would need to be a kind of error version of "Then", which could also come after the "Then" event. Javascript calls this "catch".
- I'm not sure the name "Then" is the best name - it's the term Javascript uses, but it could confuse beginners who often want to figure out how to make an "If - then" type logic (which is basically just a normal event - "if conditions true, then run actions"). It would be especially confusing that "Then" is a trigger. Other trigger names could be "Next", "After", "On done"...
A different idea I had was to make asynchronous actions like the "Wait" system action, except instead of just waiting, it would be processing some async action. I think this is limited though, since it makes it difficult to run asynchronous actions in parallel - if an event had 3 async actions, this method would force them to run one after the other in sequence, rather than starting them all at once and firing triggers as each completes (important for best performance and multi-core usage). So I think the "Then" event is a better idea.
Does anyone have any thoughts about this? Good idea or bad idea? Perhaps there's an even better way it could be approached?