packages feed

mischief-assets-0.1.0.0: src/Mischief/Assets/Tutorial/Kdl.hs

{-# OPTIONS_GHC -Wno-unused-imports #-}

-- |
-- [Previous Chapter: Asset Control Flow]("Mischief.Assets.Tutorial.Control")
--
-- [Next Chapter: Asset Control Flow]("Mischief.Assets.Tutorial.Control")
--
-- [Main Page]("Mischief.Assets")
module Mischief.Assets.Tutorial.Kdl
  ( -- * Chapter 4: Kdl Assets
    -- $intro

    -- * The KdlAsset Class
    -- $kdlasset

    -- * Manual Decoding
    -- $decoding

    -- * Collections
    -- $collection
  )
where

import KDL qualified
import Linear
import Mischief.Assets
import Mischief.ECS

-- $intro
-- [Kdl](https://kdl.dev/spec/) is the official file format used by Mischief.

-- $kdlasset
-- The KdlAsset typeclass is a helper for defining assets that are loaded from .kdl files without needing to parse their fields manually.
--
-- Generally, only types with named fields (records) can automatically derive it:
--
-- @
-- data Foo = Foo
--   {
--     a :: 'Int'
--     b :: 'Float'
--     c :: 'V2' 'Int'
--   }
--   deriving ('Generic', 'KdlAsset')
-- @
--
-- You can now use the @loadKdl@ function provided by the typeclass to quickly make a loadable asset:
--
-- @
-- instance 'Asset' Foo where
--   type 'Saveable' Foo = 'False'
--
--   'loadAsset' = 'loadKdl' \"foo\"
-- @
--
-- The asset itself should look something like this:
--
-- @
-- foo {
--   a 6
--   b 3.2
--   c 2 4
-- }
-- @

-- $decoding
-- You can write custom kdl decoders using the [kdl-hs]("KDL") library.
--
-- For instance, this is how you could decode the asset from the previous section:
--
-- @
-- instance 'KdlAsset' Foo where
--   'decodeKdl' path = KDL.'KDL.children' $ do
--     a <- KDL.'KDL.argAt' \"a\"
--     b <- KDL.'KDL.argAt' \"b\"
--     c <- KDL.'KDL.nodeWith' \"c\" KDL.'KDL.nodeDecoder'
--     pure $ Foo {a, b, c}
-- @
--
-- Note that here we can use @"KDL.nodeDecoder"@ because @V2 a@ has a @KDL.'KDL.DecodeNode'@ instance. Otherwise you'd need
-- to parse it manually, like the others.
--
-- The @path@ argument is used to decode references to other assets. For instance, if @Foo@ also had this field:
--
-- @
-- bar :: 'AssetRef' Bar
-- @
--
-- You'd decode it like this:
--
-- @
-- bar <- 'KDL.argAtWith' $ \"bar\" $ 'decodeRef' path
-- @
--
-- For KdlRefs you use 'decodeKdlRef' instead.

-- $collection
-- A Kdl Collection is a map of nodes of the same type.
--
-- For instance, this field:
--
-- @
-- a :: 'KdlCollection' 'Int'
-- @
--
-- Expects something that looks like this:
--
-- @
-- a {
--   name1 4
--   name2 6
--   name3 5
--   ...
-- }
-- @
--
-- You can use @'colGet'@ to try and get the value of a node from a collection by name. Or @'colGetMany'@ to get the
-- value of all nodes with the given name.