# Extending the System

## Overview

A procedural animation feature consists of 2 entities:

* **FPSAnimatorLayerSettings:** a Scriptable Object that contains all the data.
* **IAnimationLayerJob:** a struct that executes custom animation logic.

{% hint style="success" %}
**Tip**: the framework uses the Animation Job System, which ensures solid performance even with a large number of characters.
{% endhint %}

If you open up the source code of the framework, you will notice that every layer has its own folder with 2 .cs files:

<figure><img src="https://784345943-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxcUmJ78NSw1bSUlSO9oP%2Fuploads%2FXJ09sOiLC5TQCFQEzGoV%2Fimage.png?alt=media&#x26;token=a298a7cb-98e3-46c2-8da8-673ccbde1cf7" alt=""><figcaption><p>AdditiveLayer example.</p></figcaption></figure>

**FPSAnimatorLayerSettings** class is responsible not just for containing the data, but for instantiating the **IAnimationLayerJob** as well:

{% code title="AdditiveLayerSettings.cs" %}

```csharp
public class AdditiveLayerSettings : WeaponLayerSettings
{
    ...
    public override IAnimationLayerJob CreateAnimationJob()
    {
        return new AdditiveLayerJob();
    }
}
```

{% endcode %}

**CreateAnimationJob()** method must return a new instance of the desired **IAnimationLayerJob**-type. When you link a new **Animator Profile**, the system iterates over all animation features (*Layer Settings*) and then invokes the *CreateAnimationJob()* method to create the *Layer State*.

## Example

First, create a new **FPSAnimatorLayerSettings**-derived class for data, and **IAnimationLayerJob**-implemented struct:

{% code title="YourFeatureLayerSettings.cs" %}

```csharp
public class YourFeatureLayerSettings : FPSAnimatorLayerSettings
{
    //Define your settings here, including the KRigElements.
    public KRigElement myRigElement;

    public override IAnimationLayerJob CreateAnimationJob()
    {
        return new YourAnimationLayerJob();
    }
    
#if UNITY_EDITOR
    public override void OnRigUpdated()
    {
        base.OnRigUpdated();
        
        // (!) Always update KRigElements here.
        // Called when a rig asset is updated/changed.
        UpdateRigElement(ref myRigElement);
    }
#endif
}
```

{% endcode %}

{% code title="YourAnimationLayerJob.cs" %}

```csharp
public struct YourAnimationLayerJob
{
    private YourFeatureLayerSettings _settings;
    private LayerJobData _jobData;
    private TransformStreamHandle _yourBoneHandle;
        
    // Use this method for custom animation logic.
    public void ProcessAnimation(AnimationStream stream)
    {
    }
    
    // Use this for modifying root motion.
    public void ProcessRootMotion(AnimationStream stream)
    {
    }
    
    // This method is called when a new profile is linked.
    public void Initialize(LayerJobData newJobData, FPSAnimatorLayerSettings settings)
    {
        _settings = (AdditiveLayerSettings) settings;
        _jobData = newJobData;
        
        Transform bone = newJobData.rigComponent.GetRigTransform(settings.myRigElement);
        _yourBoneHandle = newJobData.animator.BindStreamTransform(bone);
    }
    
    public AnimationScriptPlayable CreatePlayable(PlayableGraph graph)
    {
        return AnimationScriptPlayable.Create(graph, this);
    }
    
    // Make sure to return a reference to the active asset.
    // It will be used by the FPSBoneController to compute a layer weight.
    public FPSAnimatorLayerSettings GetSettingAsset()
    {
        return _settings;
    }
    
    // Use this method to update job data when a layer is linked.
    public void OnLayerLinked(FPSAnimatorLayerSettings newSettings)
    {
    }
    
    // Use this method when a new weapon or item is equipped.
    public void UpdateEntity(FPSAnimatorEntity newEntity)
    {
    }
    
    // Use this method before the main update to gather input data.
    public void OnPreGameThreadUpdate()
    {
    }
    
    // Use this method to update playable data and gather game thread data.
    public void UpdatePlayableJobData(AnimationScriptPlayable playable, float weight)
    {
        _jobData.weight = weight;
        playable.SetJobData(this);
    }
    
    // Use this method when a finalized pose is required.
    public void LateUpdate()
    {
    }
    
    // Use this method to dispose data manually.
    public void Destroy()
    {
    }
}
```

{% endcode %}

***

In the next chapter, we will learn how to work with the demo project.
