> For the complete documentation index, see [llms.txt](https://docs.coherence.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coherence.io/0.9/api-reference/network-sdk/custombindings.md).

# Custom bindings (advanced)

{% hint style="info" %}
This is an **advanced** topic that aims to bring access to **coherence**'s internals to the end user.
{% endhint %}

`CustomBindingProviders` are editor classes that tell **coherence** how a specific component should expose its bindings and how it generates baked scripts.

For example, we could create a custom binding provider for our `Health` component:

```csharp
using UnityEngine;

public class Health : MonoBehaviour
{
    public int health;
}
```

```csharp
using UnityEngine;
using Coherence.Toolkit;

[CustomBindingProvider(typeof(Health))]
public class HealthBindingProvider : CustomBindingProvider
{
    // check the CustomBindingProvider base class to
    // explore the possibilities!
}
```

{% hint style="info" %}
Place `CustomBindingProviders` inside an editor folder.
{% endhint %}

We can add additional (custom) bindings:

```csharp
using Coherence.Toolkit;
using System.Collections.Generic;
using UnityEngine;

[CustomBindingProvider(typeof(Health))]
public class HealthBindingProvider : CustomBindingProvider
{
    public override void FetchDescriptors(List<CustomBinding.Descriptor> descriptors)
    {
        base.FetchDescriptors(descriptors);
        descriptors.Add(new CustomBinding.Descriptor("myCustomBinding", typeof(int))
        {
            bakedSyncScriptGetter = "myCustomBindingGet",
            bakedSyncScriptSetter = "myCustomBindingSet",
            coherenceComponentName = "MyCustomBinding",
            coherenceComponentFieldName = "value",
            schemaComponentFieldName = "value",
        });
        descriptors.Add(new CustomBinding.Descriptor("debugBinding", typeof(bool))
        {
            bakedSyncScriptGetter = "debugBindingGet",
            bakedSyncScriptSetter = "debugBindingSet",
            coherenceComponentName = "DebugBinding",
            coherenceComponentFieldName = "value",
            schemaComponentFieldName = "value",
        });
    }
}
```

{% hint style="info" %}
In order for these new custom bindings to work on reflected mode, we'll need to implement a runtime serializer that understands how to deal with them.
{% endhint %}

Check the `CustomBinding.Descriptor` API for further properties, like interpolation or marking the binding as required.

### CustomBindingRuntimeSerializer

For custom bindings to work on reflected mode, we need to implement how their values are serialized and deserialized at runtime:

```csharp
using UnityEngine;
using Coherence.Toolkit;
using Coherence.Entity;
using Coherence.SimulationFrame;

// this class defines how reflected mode serializes and deserializes Health's custom bindings

public class HealthRuntimeSerializer : CustomBindingRuntimeSerializer
{
    public override void Serialize(CustomBinding customBinding, ICoherenceComponentData componentData)
    {
        var health = customBinding.component as Health;

        if (customBinding.descriptor.name == "debugBinding")
        {
            Debug.Log("[HEALTH] Serializing debugBinding");
        }
        else if (customBinding.descriptor.name == "myCustomBinding")
        {
            // in this example, lets send myCustomBinding as "health" over the network
            var fi = componentData.GetType().GetField("value");
            fi.SetValue(componentData, health.health);
        }
    }

    public override void Deserialize(CustomBinding customBinding, ICoherenceComponentData componentData, long clientFrame)
    {
        var health = customBinding.component as Health;

        if (customBinding.descriptor.name == "debugBinding")
        {
            Debug.Log("[HEALTH] Deserializing debugBinding");
        }
        else if (customBinding.descriptor.name == "myCustomBinding")
        {
            var fi = componentData.GetType().GetField("value");
            var v = (float)fi.GetValue(componentData);
            // we take the value of myCustomBinding, which we know we serialized with the value of health
            // in this example, we just do some custom logic: updating the isAlive bool with it
            health.isAlive = v > 0;
        }
    }

    public override void Interpolate(CustomBinding customBinding, double time)
    {
    }

    public override void SetToLastSample(CustomBinding customBinding)
    {
    }
}
```

{% hint style="warning" %}
`CustomBindingRuntimeSerializers` should be placed in a non-editor folder.
{% endhint %}

Once we have our runtime serializer, we need to make our binding provider use it:

```csharp
using Coherence.Toolkit;
using System.Collections.Generic;
using UnityEngine;

[CustomBindingProvider(typeof(Health))]
public class HealthBindingProvider : CustomBindingProvider
{
    public override CustomBindingRuntimeSerializer CustomBindingRuntimeSerializer => new HealthRuntimeSerializer();

    public override void FetchDescriptors(List<CustomBinding.Descriptor> descriptors)
    {
        base.FetchDescriptors(descriptors);
        descriptors.Add(new CustomBinding.Descriptor("myCustomBinding", typeof(int))
        {
            bakedSyncScriptGetter = "myCustomBindingGet",
            bakedSyncScriptSetter = "myCustomBindingSet",
            coherenceComponentName = "MyCustomBinding",
            coherenceComponentFieldName = "value",
            schemaComponentFieldName = "value",
        });
        descriptors.Add(new CustomBinding.Descriptor("debugBinding", typeof(bool))
        {
            bakedSyncScriptGetter = "debugBindingGet",
            bakedSyncScriptSetter = "debugBindingSet",
            coherenceComponentName = "DebugBinding",
            coherenceComponentFieldName = "value",
            schemaComponentFieldName = "value",
        });
    }
}
```

### Extending and inheriting CustomBindingProviders

You can extend an already existing `CustomBindingProvider`. For example, **coherence** ships with a `CustomBindingProvider` for Transforms:

```csharp
using System.Collections.Generic;
using Coherence.Toolkit;
using UnityEngine;

[CustomBindingProvider(typeof(Transform))]
public class CustomTransformBindingProvider : CustomBindingProvider
{
    public override void FetchDescriptors(List<CustomBinding.Descriptor> descriptors)
    {
        base.FetchDescriptors(descriptors);

        // your changes
    }
}
```

This way, you can define additional rules on how you want to treat your Transforms, for example.

Any amount of `CustomBindingProviders` can be registered over the same component, but only one being used. The one being used, is resolved by a priority integer that you can specify in the `CustomBindingProvider` attribute. The class with the higher priority defined in the attribute will be the only provider taken into account:

```csharp
[CustomBindingProvider(typeof(Transform), 1)]
```

The default priority is set at `0`, and coherence's internal `CustomBindingProviders` have a priority `of -1`.

To understand how these APIs are used, check out `TransformBindingProvider` and `AnimatorBindingProvider`, both shipped with the **coherence** SDK (*\<package>/Coherence.Editor/Toolkit/CustomBindingProviders*).
