mischief-assets
Safe HaskellNone
LanguageGHC2024

Mischief.Assets.Tutorial.Control

Description

Synopsis

    Chapter 3: Asset Control Flow

    Some pointers on controlling the logic control flow when working with assets.

    Active vs. Passive Querying

    Attempting to query for an asset will, by default, prompt the asset to load. This is called active querying.

    For instance, running this every frame:

    foo <- asset @Foo "foo.kdl"
    

    Will prompt Foo to start loading if it hasn't yet.

    Assuming that it takes it less than a frame to load, this should be returning a Just Foo starting with the second frame.

    This mechanism is extremely powerful when used in conjunction with queries, via qasset, since queries are designed to stop executing when something you're trying to grab isn't available:

    query_ $ do
      foo <- qasset @Foo getB
      qlift $ info [i|Reading asset: #{foo}|]
    

    You can choose to use passive querying, through the equivalent functions ending in '. Such as asset' and qasset'. These functions will attempt to grab the asset, but they will not prompt it to load.

    Recursive Loading

    By default, each asset is loaded lazily. Meaning the least possible amount of I/O operations will be performed in order to get the data you need.

    If asset A contains a reference to asset B, neither load nor asset of A will attempt to load B. You can alternatively use the dedicated loadRec and assetRec which will trigger a recursive loading sequence.

    For all assets you define, you are responsible for specifying the references that will be loaded in such a case. For instance:

    data Foo = Foo
      {
        i :: Int,
        ref1 :: AssetRef Bar
        ref2 :: KdlRef Baz
      }
    
    instance Asset Foo where
      rec foo = do
        addRec foo.ref1
        addRec $ toRef foo.ref2
    

    Events

    You can spawn observers that listen to the OnLoad events, which is triggered each time an asset is loaded.

    onFoo :: OnLoad Foo -> System
    onFoo event = ...
    

    Since assets are components, you can also listen to OnAdd, OnSet, and so on.

    One-Shot Observers

    You can use runWhen and similar functions to run a system when a specific asset (or group of assets) has been loaded, like so:

    runWhenOne
      (
        foo <- qasset @Foo "foo.kdl"
        bar <- qasset @Bar "bar.kdl"
        pure (foo, bar)
      )
      (\(foo, bar) -> do
        ...
      )
    

    Note however, that each time this function is ran, an instance of your query will be scheduled to run at every sync point until it returns a result. In order to not waste a large amount of resources, this should only be used in one-time logic such as on Startup or in an Observer, rather than in logic that runs at a fixed interval.

    Next Chapter: Kdl Assets