## Declaring one

A synced value is a field on a behaviour, or an auto-property if you prefer:

```csharp
private Synced<int> score = new Synced<int>();

public Synced<string> Message { get; } = new Synced<string>();
```

Both become one replicated variable named after what you wrote. A property with accessors of its
own cannot work and is refused: Udon replicates a named variable, and an accessor is code that runs
fresh on each client.

It has to be on the behaviour. A synced value on a plain class the behaviour uses would compile and
never replicate, so that is refused too, naming the field.

## What can go in one

Every C# primitive, `string`, `Vector2`, `Vector3`, `Vector4`, `Quaternion`, `Color`, `Color32`,
`VRCUrl`, and arrays of all of them. That is VRChat's list, not this package's. Anything else is
refused while compiling rather than dropped while running.

A starting value goes in the constructor:

```csharp
private Synced<int> lives = new Synced<int>(3);
```

## Reading and writing

```csharp
score.Value = score.Value + 1;
```

Writing replicates. There is no serialization call to pair it with, which removes the way a synced
value silently stops travelling: assigning and forgetting the call. Several writes in one frame
still cost one send, because VRChat coalesces them.

**Only the owner writes.** On any other client the assignment stays local, which is the one Udon
rule this package does not hide. Either take ownership first with `Ownership.Claim(gameObject)`, or
put the value on an object whose owner is already the right client.

## Hearing a change

```csharp
score.Subscribe(OnScoreChanged);
```

Every client's handler runs when the value arrives, including the client that wrote it. Subscribing
twice with the same handler adds nothing, and `Unsubscribe` removes it.

A handler that also wants what the value changed *from* takes both:

```csharp
score.Subscribe(OnScoreChanged);

private void OnScoreChanged(int previous, int current)
{
    scoreboard.Show(current, current - previous);
}
```

Before the first change the old value is the type's own default, because there was nothing before
it. Both shapes can be subscribed to the same value at once, and both run.

**Handlers run once the whole update has landed.** VRChat applies a batch one variable at a time,
so a handler that ran as each value arrived could read a sibling that is still the previous value.
Measured with two clients before this existed: a subscriber saw its counter arrive beside a string
that was still empty. Now a handler can read every other synced value on the behaviour and see the
update it came in.

## Arrays

An array replicates as a whole value, so replacing it works the way you expect:

```csharp
private Synced<int[]> scores = new Synced<int[]>(new int[8]);

scores.Value = fresh;
```

Writing one element is the case the compiler cannot see from the assignment alone, so say it:

```csharp
scores.Value[2] = 7;
scores.MarkChanged();
```

`MarkChanged` replicates and tells this client's subscribers, exactly as assigning the whole array
would have. Without it the change stays on the writing client, silently.

## Ownership

| | |
|---|---|
| `Ownership.IsMine(gameObject)` | Whether this client may write this object's synced values |
| `Ownership.Claim(gameObject)` | Take it, if nothing refuses |
| `Ownership.GiveTo(player, gameObject)` | Hand it to somebody |
| `Ownership.Of(gameObject)` | Who owns it |

A transfer can be refused by overriding `OnOwnershipRequest` and returning `false`. `MasterOwned` is
that override already written: derive from it and only the arbitrating client can own the object,
which is how a world keeps a value nobody else may write.

ClientSim does not raise ownership requests. That one has to be tested in an uploaded world.
