LogoLogo
⚠️ Outdated documentationGo to latestHomeAPI
SDK 1.3
SDK 1.3
  • Welcome
  • Overview
    • Features
    • Roadmap
  • Getting started
    • Get the Unity SDK
    • Setup a project
      • Scene setup
      • Prefab setup
      • Sample connection UIs
      • Local development
        • Local testing using Builds
        • Local testing via Unity's Multiplayer Play Mode (MPPM)
        • Local testing via ParrelSync
      • Test in the cloud
        • Deploy a Replication Server
        • Share builds
    • Video tutorials
    • Samples and tutorials
      • Package samples
      • First Steps tutorial
        • 1. Basic syncing
          • 1.2. Animation parameters
          • 1.3. Sending commands
        • 2. Physics / Authority transfer
        • 3. Areas of interest
        • 4. Parenting entities
        • 5. Complex hierarchies
        • 6. Persistence
      • Campfire project
        • Game mechanics
        • Leveraging object pooling
        • Remote interactions: Chairs
        • Remote interactions: Trees
        • A unique object with complex state
        • Custom instantiation and destruction
        • Running a server-side NPC
        • Playing audio and particles
        • A simple text chat
      • Beginner's guide to networking
  • Manual
    • Unity Components
      • CoherenceSync
      • CoherenceBridge
      • CoherenceNode
      • CoherenceLiveQuery
      • CoherenceTagQuery
      • PrefabSyncGroup
      • CoherenceInput
      • Order of execution
    • Networking state changes
      • Supported types
      • Messaging with Commands
      • Syncing child GameObjects
      • Animation
      • CoherenceSync references
      • [Sync] and [Command] Attributes
      • [OnValueSynced] Attribute
      • Creating your own syncable member
      • Custom Component Actions
      • Rigid Bodies
      • Interpolation
    • Authority
      • Authority transfer
      • Server-authoritative setup
    • Lifetime
      • Persistence
      • Uniqueness
      • Example: A global counter
    • Parenting network entities
      • Direct children CoherenceSyncs
      • Deeply-nested CoherenceSyncs
      • Nesting Prefabs at Edit time
    • Asset management
      • Instantiate via
      • Load via
      • Instantiating from CoherenceSyncConfig
    • Scene management
    • Baking (code generation)
    • Replication Server
      • Rooms and Worlds
      • Replication Server API
    • Simulators (Servers)
      • Scripting: Client vs Simulator
      • Run local Simulators
      • World Simulators
      • Room Simulators
      • Simulator slugs
      • Multi-Room Simulators
      • Build and Deploy
      • Command-line arguments
    • Client Connections
    • Optimization
      • Areas of Interest
      • Level of Detail (LOD)
      • Profiling
      • Simulation Frequency
    • Project Settings
    • Advanced topics
      • Big worlds
        • World Origin Shifting
        • Load balancing
      • Competitive games
        • Simulation Frame
        • Determinism, Prediction and Rollback
      • Team workflows
        • Version Control integration
        • Continuous Integration
      • Schema explained
        • Specification
        • Field settings
        • Archetypes
      • Code Stripping
      • Command-line interface tools
      • Single-player gameplay
    • Scripting API
  • Hosting
    • Choosing where to host
    • coherence Cloud
      • Online Dashboard
      • Manage Worlds
      • Configure Rooms
      • Lobbies
      • Game Services
        • Account
        • Key-Value Store
      • coherence Cloud APIs
        • Worlds API
        • Rooms API
        • Lobbies API
        • Game Services
          • Authentication Service (Player Accounts)
          • Key-value store
    • Peer-to-peer
      • Implementing Client hosting
  • Support
    • Release notes
    • Glossary
    • Unreal Engine support
    • WebGL support
    • ECS / DOTS support
    • Known issues and troubleshooting
    • Upgrade guide
      • Upgrade 1.2 -> 1.3
      • Upgrade 1.1 -> 1.2
      • Upgrade 1.0 -> 1.1
      • Upgrade 0.10 -> 1.0
      • Upgrade 0.9 -> 0.10
    • Credit cost & pricing
    • Report a bug
Powered by GitBook
On this page
  • Our use case
  • The code
  • What could go wrong?

Was this helpful?

Export as PDF
  1. Getting started
  2. Samples and tutorials
  3. Campfire project

Remote interactions: Chairs

Was this helpful?

Topics covered

| |

In a networked game, an object's logic is always run by one node on the network, whether it's a Client or a Server (which we call a in coherence). We say that the node "has authority" on the network entity.

There are cases where it makes sense to transfer authority, like it happens in this project with objects that can be picked up. When the player grabs an object, the Client performing it requests authority over the network entity. Once it gets authority it starts running its scripts and has full control over it. This is a very good way to go when only one player can interact with a certain object at a given time.

For more info, check in the First Steps project.

However, there are cases when we don't want to change who has authority on an entity. In the case of an object that many players can interact with at the same time, it wouldn't make sense to continuously move authority between nodes.

The interaction with such remote entities then needs to happen entirely through .

Our use case

In this project, it is the case of the chairs placed in the scene. The first Client or Simulator to connect will take authority over them, and it will keep it until they disconnect.

When a player wants to sit down on a chair, they inform the Authority that they are doing so. The client holding authority will then set the chair as busy, which prevents other players from sitting on it next time they try.

However, for the sake of simplicity and to illustrate the point, we intentionally left this interaction a bit flaky. Can you guess why? What could go wrong with this setup?

The code

The action originates in SitAction.cs:

public void Sit(Chair chairComponent)
{
    if (!_chair.isBusy)
    {
        _chair.Occupy();
    }
{

SitAction checks if the isBusy property of the chair is set to true (by the authority, of course). If so, it means someone else is already sat on the chair. If false, we can sit. So it invokes Chair.Occupy().

[Sync] public bool isBusy;

And further down, the essence of the interaction:

public void Occupy()
{
    if (sync.HasStateAuthority) ChangeState(true);
    else sync.SendCommand<Chair>(nameof(ChangeState), MessageTarget.AuthorityOnly, true);
}

public void Free()
{
    if (sync.HasStateAuthority) ChangeState(false);
    else sync.SendCommand<Chair>(nameof(ChangeState), MessageTarget.AuthorityOnly, false);
}

[Command(defaultRouting = MessageTarget.AuthorityOnly)]
public void ChangeState(bool newBusyState)
{
    isBusy = newBusyState;
    // Deactivates the collider so the chair can't be even selected
}

So both when occupying a chair (Occupy()) or standing up (Free()), the player executing the action invokes the ChangeState method, either directly or as a Network Command - depending if they are the one with authority.

So one way or the other, ChangeState gets executed on the authority, who sets the isBusy property to its new value. On the next coherence update, the property will be sent to the other Clients.

What could go wrong?

The answer: Clients are using the isBusy property as a check for whether they can sit or not. It is possible that two players will approach a chair at the same time, check if isBusy is false (and yes, it will be false), at which point they will inform the authority that want to sit down on it.

The authority performs no additional checks, so you will see both players successfully sitting on the chair, overlapping on each other.

Thankfully we also coded the rest of the interaction so that this doesn't break the game. So while this incidence and the consequences for this interaction are low-risk, if you're looking to create a more robust system it could make sense to implement a check on the authority, and have the Client wait for an answer before they sit down.

You will find the code of chairs in Chair.cs, located in Scripts/Objects. Looking into it, we find the property used as a gate:

We do this in other parts of the demo, like when chopping a tree or when picking up an object. Check the following to explore this similar but more complex use case.

📁
section on chopping trees
Authority
Authority transfer
Network Commands
Simulator
the lesson about transferring authority
Network Commands