Menu

Pipelines

g-dollar

A Pipeline is a fancy name for an asynchronous send/receive model, where the receive side uses marker interfaces to determine what to call on the received object.

To encourage indirect coupling, you specify the names of target components via a route, so the call-site determines which other components "see" the pipeline GO on "the other end".

AGE has these pipelines:

  • Install: for loading data, connecting to AGE and other GOs.
  • Uninstall: for reversing the effect of Install.
  • Event: for inter-GO communication.

The goals of the Pipelines:

  • Asynchronous design acknowledges the task of resource acquisition and offloads that work to a different thread.
  • Easy to target a GO at the call site. A call to install/uninstall/event() does it all!
  • Require minimum information "in hand"; just the GO to operate on, and the Installer interface.
  • Standard way for everything to be initialized and enter/exit the system.
  • Uniform "top-level context" (threading, locking, interfaces) to perform these actions.

Pipelines

This interface is the entry point to all pipelines.

Even though the pipeline requests are asynchronous, they are not multi-threaded, meaning none of the requests are executed until after the current method completes. Because of the apartment model, request ordering is preserved, and top-level contexts ensure synchronization for atomic model updates.

Marker Interfaces

Game objects (hereafter GO) opt-in for AGE services by implementing the marker interface of each required service. These interfaces follow the naming pattern RequireXXX where XXX represents the service.

RequireResourceLoader

Indicates requirement for asynchronous resource loading.

RequireTimer

Indicates requirement for establishing multiple timers.

TimerCallback

Indicates the GO itself is a timer to be registered.

RequireLocatable

Indicates requirement for registering multiple name/GO mappings in the Locator.

Individual components can use additional marker interfaces as necessary, e.g. to conditionally accept a routed GO on its LoadedCallback.

Install Pipeline

The Install pipeline is started by calling the install() method, and passing the GO to install. The GO should be minimally initialized at this point, because the Pipeline will take over the actual "work" of initializing.

The first stop on the Install Pipeline is the Resource Loader task, for the time-consuming work of initializing a GO from resources, e.g. texture bitmaps, object models, etc.

Load Request

The LoadObject message contains the information used by the tasks in the Install Pipeline:

  • the GO to target.
  • a reply-to TaskChannel to notify when complete.
  • a LoadedCallback to execute in that context when it receives this message. The Game Cycle uses a LoadedCallback that's outlined below.
  • an optional list of bind targets, called a route, to have their LoadedCallback invoked.

Loaded Callback

This is called for every GO that completes the install pipeline. It is called on the Game Cycle's thread, so thread-safety is necessary if interacting with the UI (or other) thread of the application.

This is a top-level context with the update lock held.

Default Behavior

The install pipeline proceeds as follows (the thread executing is in parentheses):

  1. (Caller) Call the install() method, which sends a message to the Resource Loader task and returns. the reply-to target is the Game Cycle, and the LoadedCallback is the remainder of the steps from step 3. Do not access the GO after this point, until objectLoaded() (step 4) or a routed LoadedCallback is called (step 8).
  2. (Resource Loader) If RequireResourceLoader is implemented, invokes the GO.load() method, passing ResourceLoader and Resources interfaces. If not implemented, no action is taken; this is done to maintain the order of install calls with their callbacks. When complete, the load request is passed to the reply-to target (Game Cycle).
  3. (Game Cycle) Obtain the update lock for the remainder of the steps.
  4. (Game Cycle) call the objectLoaded() method, passing the GO and error status. This is a good place to trigger additional installs that depend on a GO being completely installed before certain methods can be called successfully.
  5. (Game Cycle) if GO.locatable flag is set, register with Locator.
  6. (Game Cycle) if RequireLocatable is implemented, register mappings with Locator.
  7. (Game Cycle) if RequireTimer or TimerCallback are implemented, register with TimerService. The RequireTimer takes priority here, so a GO implementing both interfaces must put itself in RequireTimer.
  8. (Game Cycle) if the request contains a route, obtain each GO from the Locator and pass installed GO to its LoadedCallback (if implemented).

Uninstall Pipeline

The uninstall pipeline reverses the operations of the install pipeline, but does not execute anything in the Resource Loader thread. Use the same route from the install() call.

Note that uninstall() is done by name and not by GO reference. To participate in the Uninstall pipeline the GO must be in the Locator, or no callbacks are invoked.

This is a top-level context with the update lock held.

Unloaded Callback

The dual of LoadedCallback is UnloadedCallback. This is meant to undo whatever the effect of LoadedCallback was.

Default Behavior

  1. (Game Cycle) Obtain the update lock for the remainder of the steps.
  2. (Game Cycle) call the objectUnloaded() method, passing the GO and error status.
  3. (Game Cycle) if RequireTimer or TimerCallback are implemented, unregister with TimerService. The RequireTimer takes priority here, so a GO implementing both interfaces must put itself in RequireTimer.
  4. (Game Cycle) if RequireLocatable is implemented, remove mappings from Locator.
  5. (Game Cycle) if GO.locatable flag is set, remove from Locator.
  6. (Game Cycle) if the request contains a route, obtain each GO from the Locator and pass installed GO to its UnloadedCallback (if implemented).

Event Pipeline

This pipeline is for making asynchronous requests for additional code to execute. This makes it convenient to schedule something to happen after the current method completes, and keeps the model in a consistent state, by not mutating it at that time.

The GameObject class is reused here to represent an event.

To participate in the Event pipeline, a target GO must be in the Locator and implement the EventCallback interface. The Event pipeline does not check for any other marker interfaces.

This is a top-level context with the update lock held.

Event Request

This is analogous to the LoadObject request. The most-important part of this is the route.

Event Callback

This callback gets the GO that was sent as the event. This is an excellent place to put game logic.

Default Behavior

This is how the Game Cycle thread handles Event Requests:

  1. (Game Cycle) Obtain the update lock for the remainder of the steps.
  2. (Game Cycle) call the objectEvent() method, passing the GO. This is a good place to trigger additional installs/uninstalls/events that are unrouted or you want to process it before any route targets do.
  3. (Game Cycle) if the event request contains a route, obtain each GO from the Locator and pass event GO to its EventCallback (if implemented).

Related

Wiki: Home
Wiki: Making a Game with AGE

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.