# Custom Signals

A **Signal source** adds one way to produce or write an existing value type. Once discovered, it works in every field that accepts that type.

## Adding a source to an existing type

Derive from the type's abstract base, such as `TypeNumber`, `TypeString`, or `TypeGameObject`, and override `Get`. This example assumes `MyComponent` exposes a numeric `Value` property:

```cs
using System;
using UnityEngine;
using VisualScript.Icons;
using VisualScript.Runtime;

[Get]

[Title("My Value")]
[Category("My System/My Value")]
[Description("The current value of the custom system")]

[Image(typeof(IconNumber), ColorTheme.Type.Teal)]

[Serializable]
public class TypeNumberMyValue : TypeNumber
{
    [SerializeField] private GetGameObject m_Source = new GetGameObject();

    public override double Get(Args args)
    {
        MyComponent component = this.m_Source.Get<MyComponent>(args);
        return component != null ? component.Value : 0d;
    }

    public override string ToString() => $"{this.m_Source} value";
}
```

`Get` returns the component's `Value`, or `0` when the resolved object has no `MyComponent`. Three parts define the source's editor and runtime behavior:

- **`[Get]`** adds the type to Get dropdowns. Add `[Set]` and override `Set` for a writable source.
- **`Get(Args)`** produces the value from the current context.
- **`ToString()`** returns the phrase shown in the collapsed field.

## Writable sources

Add `[Set]` and implement `Set` only when the underlying value is writable. This partial example keeps the source field and `Get` implementation from the previous example:

```cs
[Get] [Set]

[Serializable]
public class TypeNumberMyValue : TypeNumber
{
    public override double Get(Args args) { /* … */ }

    public override void Set(double value, Args args)
    {
        MyComponent component = this.m_Source.Get<MyComponent>(args);
        if (component != null) component.Value = value;
    }
}
```

`Set` writes the supplied value when `MyComponent` exists. Leave `[Set]` off read-only sources so designers don't select a write operation that can't change the value.

## Signals must be pure

Like [Conditions](conditions.md), `Get` can be called many times per frame. A binding may read it every frame for each subscription, so reading a Signal must not change state.

!!! warning "Side effects make Get depend on evaluation frequency"
    A `Get` that spawns an object, writes a variable, or advances state changes the game every time it's evaluated. That frequency depends on how designers use the Signal.

Evaluation cost matters for the same reason. If a binding polls a `Get` that raycasts, it repeats that raycast every frame.

## Reporting changes

Override `Subscription` to declare how the Signal detects change. This is what makes **On Number Change** work with your source. Choose the mode based on the available notifications and evaluation cost:

| Mode | Behavior | Cost |
| :--- | :--- | :--- |
| `None` | Not bindable. The default. | No subscription work |
| `OnChange` | Polled each frame; fires when the value differs. | One `Get` per frame per subscriber |
| `OnUpdate` | Fires every frame regardless. | One callback per frame |
| `OnFixedUpdate` | Fires every physics step. | One callback per step |
| `Custom` | Your implementation subscribes and unsubscribes. | Depends on the implementation |
| `OnEditorChange` | Fires when edited in the Inspector. Editor only. | No runtime subscription work |

Use `OnChange` to poll a cheap `Get` implementation:

```cs
protected override SubscriptionMode Subscription => SubscriptionMode.OnChange;
```

`OnChange` reads the value every frame and notifies subscribers when it differs. When the underlying source already raises an event, use `Custom` to avoid that polling. Override `OnSubscribe` to register the callback and return its subscription `Guid`, then release it in `OnUnsubscribe`.

!!! warning "Don't put an expensive Get behind OnChange"
    `OnChange` polls. Declaring it on a Signal that searches the scene means that search runs every frame for every binding. Either use `Custom`, or leave it as `None` so designers can't accidentally bind to it.

## Editor previews

`GetPreview(GameObject source)` returns a value for the Inspector outside Play mode. Implement it when the field would otherwise give no indication of its result.

## Adding a whole new value type

A new value type requires four pieces:

1. An abstract `TypeMyThing : TType<MyThing>` base.
2. A `GetMyThing : TSignalGet<TypeMyThing, MyThing>` wrapper, and `SetMyThing` if it's writable.
3. At least one concrete source — usually a constant and a variable lookup.
4. An editor drawer implementing `ITypeDrawer` so the field renders properly.

Reserve this work for a type used throughout the project. For one field, prefer a **Scriptable Object** Signal or a **Game Object** Signal that resolves a component.

## Checklist

- `[Serializable]`, derived from the matching `Type…` base.
- `[Get]`, `[Set]`, or both, with matching overrides.
- `Get` is pure and proportionately cheap.
- `ToString()` returns a readable phrase.
- `Subscription` matches the source's change mechanism and cost.

## Where to go next

- **[Bindings](../../manual/signals/bindings.md)** — follow subscription modes from the designer's perspective.
- **[Custom variable types](variables.md)** — add a value type that variables can store.
- **[Custom Conditions](conditions.md)** — implement a synchronous guard around a Signal.
