You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Now, when we go to extend an event in the engine, instead of passing the original event around, we pass an empty dictionary. The dictionary should be modified in place, but we can also support returning a new dictionary as well.
If a dict is returned, we must assume that the intent is to replace the existing context dict.
We pass this dict or the replaced dict to the next extension in order.
ExtensionCallback=Callable[[dict], dict|None]
After we have hydrated our context dictionary, we now assemble a copy of the Event object in the engine. On first pass, I think this means using dataclass.replace() but open to ideas on how to do this more robustly.
Optionally, we can choose (or write) a "frozen_dict" operation to freeze the context_dict as well.
Benefits:
We don't need to worry about users accidentally shooting themselves in the foot by overwriting fields.
We don't need specialized type hints for a extended event type.
We can teach using TypedDict for specifying the fields you care about out of a dictionary.
The second half of this proposal is fixing the Systems API for extending events. Our general design philosophy is allowing as much declarative configuration as possible, and I strongly believe that's the right path for this. The eventual goal is something akin to:
While this method won't work directly (methods aren't defined at class definition time), something similar would be great.
I assume something akin to callback_or_string = Callable[[dict], dict | None] | str that will then call get_attr(SomeSystem, callback_or_string)(context_dict) when callback_or_string is a string.
The goal is that extending events is as simple as everything else, with better guard rails and typing.
The text was updated successfully, but these errors were encountered:
Event extensions are really cool and powerful and I like teaching about them, but they've got a bunch of roughness around the edges.
Setting them up:
__init__
with their specifically quirky__init__
signature, then call engine.register after setting up the system proper.Typing woes:
The rest of this issue describes a potential design to address many of these issues.
Events are going to be a protocol: To be a base event, you need to have a scene attribute and a context attribute:
Any additional core event data is defined by the object that defines the event. We'll use
Update
as our example:Now, when we go to extend an event in the engine, instead of passing the original event around, we pass an empty dictionary. The dictionary should be modified in place, but we can also support returning a new dictionary as well.
If a dict is returned, we must assume that the intent is to replace the existing context dict.
We pass this dict or the replaced dict to the next extension in order.
After we have hydrated our context dictionary, we now assemble a copy of the Event object in the engine. On first pass, I think this means using
dataclass.replace()
but open to ideas on how to do this more robustly.Optionally, we can choose (or write) a "frozen_dict" operation to freeze the context_dict as well.
Benefits:
The second half of this proposal is fixing the Systems API for extending events. Our general design philosophy is allowing as much declarative configuration as possible, and I strongly believe that's the right path for this. The eventual goal is something akin to:
While this method won't work directly (methods aren't defined at class definition time), something similar would be great.
I assume something akin to
callback_or_string = Callable[[dict], dict | None] | str
that will then callget_attr(SomeSystem, callback_or_string)(context_dict)
when callback_or_string is a string.The goal is that extending events is as simple as everything else, with better guard rails and typing.
The text was updated successfully, but these errors were encountered: