Sources & Overrides¶
Every world input works the same way underneath.
There is a source your game supplies, an override that can mask it, and an owner attached to that override. Read this once and the four lanes are all the same shape.
The Two Layers¶
A source is an interface you implement and hand to the brain. FaceCue polls it: whenever it needs the value, it asks.
An override is set imperatively, and it belongs to an owner. While an override is present, reads take it and never reach the source. Remove it and reads fall through to the source again.
They are layers, not alternatives. A source is the steady answer, and an override is the exception on top of it: a scripted moment that takes a character's gaze for the length of a cutscene, then gives it back to whatever was driving it before.
You can use either alone. A game that only ever sets values imperatively never implements a source, and one with a good source of its own may never set an override.
Owners¶
An override is claimed by an owner, and every lane can report which kind currently holds it.
| Owner kind | Means |
|---|---|
| None | No override. Reads reach the source |
| Anonymous | Claimed through the short form, with no owner given |
| Explicit | Claimed by a specific object |
The short form claims a shared anonymous lane. It is fine for a single system that will never contend with another, and it is the one to use while prototyping.
The owner form is what lets two systems share a character. Pass whatever is responsible for the value, usually the component making the call. Each system can then ask whether it is the one currently holding the lane instead of assuming.
Releasing¶
Three ways to give a lane back, and the difference matters.
Release…Override() gives back the anonymous lane.
TryRelease…Override(owner) gives it back only if you still hold it. This is the one to reach for. A system that has already been superseded cannot pull the value out from under whatever replaced it, so a late cleanup from something that lost the lane 10 seconds ago does nothing instead of causing a glitch.
ForceClear…Override() takes the lane back regardless of who holds it. It is administrative, for tearing down a scene or recovering from a state you no longer trust.
When Something Is Destroyed¶
You do not have to clean up after an owner that has been destroyed. On the next frame FaceCue withdraws any override whose owner no longer exists, and on the Look Target lane one whose target no longer exists. Either way the lane goes back to its source with a Vacated event, and a character does not go on looking at an object that is gone.
For whatever is left of the frame it was destroyed in, the override still holds, and the lane reads as nothing rather than falling back to the source. That is deliberate. The Vacated event reaches your game before the source takes over, so if you respond by setting a new target, the character goes straight to it instead of flicking to whatever the source was offering and then away again.
Release Deliberately Anyway
The automatic release is the safety net, not the plan. Releasing yourself happens when you meant it to, with a Released event your other systems can act on, rather than a Vacated one on the next frame.
Change Events¶
Every lane publishes an event when its override changes. Each page documents its own, with the payload that lane carries, and they all share the same set of transitions.
| Transition | What happened |
|---|---|
| Acquired | An override was claimed where there was none |
| Updated | The value changed, same owner |
| Transferred | A different owner took the lane |
| Released | Given back by the holder |
| ForceCleared | Taken back administratively |
| Vacated | Lost automatically, because the owner or the value was destroyed |
Two details are worth knowing before you write a handler.
A replacement is one event, not two. A setter that replaces stale state publishes a single Updated or Transferred, never a vacancy followed by an acquisition. You will not see a lane appear to empty and refill.
On a Vacated event, the previous owner is a destroyed object. It is kept instead of nulled so identity comparison still works, which is what lets you check whether the thing that just went away was yours. Do not dereference it. Comparing it is safe, using it is not.
Everything Lands Together¶
When several lanes change at once, every change is made first, and only then do the events go out.
Each change still raises its own event, one after another, so a handler subscribed to several lanes hears about each change separately, once per change. What every handler has in common is that it sees the character fully updated.
Say a cutscene object held both a character's look target and its dialogue state, and the object is destroyed. Both lanes are released first, and then their two events fire in turn. The look target's handler already sees the dialogue state released, and the dialogue state's handler sees the look target gone. Neither catches one lane updated and the other not yet.
If a handler sets another override, that change raises its own event after the ones already waiting, never in the middle of them.
Reading a character's state never changes it.