> For the complete documentation index, see [llms.txt](https://kinematicsoup.gitbook.io/reactor/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kinematicsoup.gitbook.io/reactor/tutorials/authoritative_client.md).

# Client Authority and State Relay

## Summary

This tutorial shows how to sync transform and animation state from one player to all other players using entity ownership and the *ksAnimationSync*, *ksOwnershipScriptManager*, and *ksAutoSpawn* components. This can be useful when you have an existing Unity-based character controller you want to use without porting it to a Reactor player controller to make it server authoritative. This tutorial uses the [Third-Person Character Controller](https://assetstore.unity.com/packages/essentials/starter-assets-third-person-character-controller-urp-196526) from Unity's starter assets, though the scripts could be used with other controllers as well.

There are drawbacks to using a client-authoritative controller instead of a server-authoritative one. Client-authoritative games are easier for players to cheat by syncing states that are not intended by the developer, and are not recommended for highly competitive play. This can be mitigated by writing [server-side validation](/reactor/examples/validators.md) of client movement, but this is outside the scope of this tutorial. Client-authoritative controllers are also not well suited for dynamic physics interactions that affect gameplay.

### Requirements

* [Reactor Requirements](/reactor/overview.md#requirements)
* A Unity URP project
* [Starter Assets - Third-Person Character Controller](https://assetstore.unity.com/packages/essentials/starter-assets-third-person-character-controller-urp-196526)

## Scene and Prefab Setup

### Open the Scene

1. Open the Playground scene from *'Assets/StarterAssets/ThirdPersonController/Scenes/Playground'*. If you want to preserve the orignal scene, save a copy of this scene.

### Create a Room

1. Right click in the hierarachy window and create a **'Reactor->Room'** game object.
2. Check 'Allow Player Spawning' in the *ksRoomType* inspector. This will allow players to spawn entities in the room that are synced to other players.

### Create the Player Prefab

1. Select the 'PlayerArmature' object.
2. Add a *ksEntityComponent*.
3. Uncheck 'Is Permanent' in the *ksEntityComponent* inspector.
4. In the inspector for the *CharacterController*, expand the 'Reactor Collider Data' foldout and set the 'Existence' to 'Client-Only'. This prevents the component from being written to server configs.
5. Add a *ksAutoSpawn* component. This will automatically spawn the game object as an entity for each player when they connect. It can only be used with prefabs with a *ksEntityComponent* in Resources or asset bundles, and requires player spawning be enabled in the *ksRoomType* inspector. We will make the game object a prefab variant in Resources later.

   * 'Spawn Owned' determines if the entity spawns with the player who created it as the owner (client authoritative) or without an owner (server authoritative). If unchecked, instances in the initial scene will not spawn per-player when they connect; only instances instantiated at runtime will spawn entities. Leave this checked.
   * 'Owner Permissions\` determines what permissions the owner has. Leave this as 'Everything'.
     * 'Transform' the owner controls the transform.

     * 'Properties' the owner can set properties.

     * 'Destroy' the owner can destroy the game object to destroy the entity for all players.

   > *You can change the owner or owner permissions on the server using* `Entity.SetOwner(player, permissions)`*.*

> *You can use the* `Room.OnPlayerSpawnEntity.Validate` *event on the server to validate player spawn requests. The* `Room.OnPlayerSpawnEntity.Complete` *event will fire after a player-spawned entity is spawned.*

> ksAutoSpawn *will only spawn entities automatically if the game object and the room object are in the same scene. If there is more than one* *connected room object in the same scene, the game object will not spawn, unless it is a descendent of one of the room objects in which case* *it will spawn in that room. You can call* `ksAutoSpawn.Spawn(room)` *to spawn an entity for the game object in a specific room, or use one* *of the* `Room.Spawn` *overloads on the client to spawn an entity for a gameobject without a* ksAutoSpawn *component. Just like when using* ksAutoSpawn, *Gameobjects spawned as entities from the client using* `Room.Spawn` *must be prefabs with a ksEntityComponent in Resources* *or asset bundles.*

6. Add a *ksAnimationSync* component. This will sync the animator parameters as properties. It requires the entity to have an owner.
   * 'Animator' lets you set a reference to the Animator to use. If you leave it blank, it will look for an Animator on the same game object as the script. Leave it blank.
   * 'Animation Property Ids' shows the range of properties used to sync animator parameters and lets you change the start of the range. Make sure these do not overlap with other property ids you are using.
   * 'Sync Layer States' will optionally sync the layer states. This is only needed if your layer animation state changes are triggered programmatically instead of by animator properties with an animator controller. Leave this unchecked.
   * 'Animation Properties' can be expanded to view the synced animation property ids, types, and names.
7. Add a *ksOwnershipScriptManager* component. This allows you to configure what happens to scripts on the object based on ownership state. It can also be added to children of the entity game object to configure their scripts.
   * Set 'Default' to 'Disable When Unowned'. This will disable scripts that don't have a different configuration on entities that are not owned locally.
   * Set 'Animator' to 'Leave Unchanged'. This will prevent the default 'Disable When Unowned' setting from disabling the *Animator* for non-locally owned entities.

> *Instead of 'Disable When Unowned' you could use 'Destroy When Unowned' to destroy the scripts for the remote players' entities. This is not* *desirable for entities whose ownership can change such as vehicles, since destroyed scripts cannot be recreated, but disabled scripts will* *be reenabled if the local player becomes the entity's owner. Sometimes destroying scripts is preferable, as disabling may not completey stop* *the script from running code as it does not remove the script or stop it from receiving messages from* `GameObject.SendMessage`. *In this case if you set* *'Default' to 'Disable When Unowned', you will also need to change the order of the* CharacterController *and* ThirdPersonController *components* *or you will get an error saying the* CharacterController *cannot be destroyed because* ThirdPersonController *depends on it.*

8. Drag the object into a *'Resources'* folder and make it a prefab variant.
9. Rename the prefab to 'Player'.

## Scripting

### Create a Script to Play Footstep Sounds

The *ThirdPersonController* script plays footstep sounds when a character walks, however we disable this script for remote players since it also tries to move the character using player inputs, which we only want to do for the local player. The sounds are played in response to animation events, and disabling the script does not prevent it from receiving the animation event messages, however because `Start` wasn't called since the script is disabled, `_controller` won't be set and will cause a null reference exception. We will remove the footsteps code from *ThirdPersonController* and move it into a new script so we can disable or destroy the *ThirdPersonController* for remote players and still have the footsteps play properly.

1. Select the 'Player' prefab.
2. Click the **'Add Component'** button in the inspector and create a new C# Script named 'Footsteps'.

*Footsteps.cs*

```c#
using UnityEngine;

public class Footsteps : MonoBehaviour
{
    public AudioClip LandingAudioClip;
    public AudioClip[] FootstepAudioClips;
    [Range(0, 1)] public float FootstepAudioVolume = 0.3f;
    private CharacterController _controller;

    private void Start()
    {
        _controller = GetComponent<CharacterController>();
    }

    private void OnFootstep(AnimationEvent animationEvent)
    {
        if (animationEvent.animatorClipInfo.weight > 0.5f)
        {
            if (FootstepAudioClips.Length > 0)
            {
                var index = Random.Range(0, FootstepAudioClips.Length);
                AudioSource.PlayClipAtPoint(FootstepAudioClips[index], transform.TransformPoint(_controller.center), FootstepAudioVolume);
            }
        }
    }

    private void OnLand(AnimationEvent animationEvent)
    {
        if (animationEvent.animatorClipInfo.weight > 0.5f)
        {
            AudioSource.PlayClipAtPoint(LandingAudioClip, transform.TransformPoint(_controller.center), FootstepAudioVolume);
        }
    }
}
```

3. Set the 'Landing Audio Clip' to *'Assets/StarterAssets/ThirdPersonController/Character/Sfx/Player\_Land'*
4. Right-click the 'Footstep Audio Clips' field in the inspector for the *ThirdPersonController* script and click *'Copy'*.
5. Right-click the 'Footstep Audio Clips' field in the inspector for the *Footsteps* script and click *'Paste'*.
6. Set 'Footsteps' to 'Leave Unchanged' in the *ksOwnershipScriptManager* inspector.
7. Remove the `OnFootstep` and `OnLand` functions from the *ThirdPersonController* script.
8. Remove the `LandingAudioClip`, `FootstepAudioClips`, and `FootstepAudioVolume` fields from the *ThirdPersonController*.

## Testing

You are now ready to test your game. You will need to use the [Unity Multplayer Play Mode](https://docs.unity3d.com/Packages/com.unity.multiplayer.playmode@1.6/manual/index.html), [ParrelSync](https://github.com/VeriorPies/ParrelSync), or build a game client with your scene added to the build in order to connect multiple clients at once. When you move your character on one client, you should see it move on other clients.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://kinematicsoup.gitbook.io/reactor/tutorials/authoritative_client.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
