Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 103 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

SDK 0.5.2

Loading...

Overview

Loading...

Loading...

Loading...

Loading...

Get Started

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Authority and communication

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Persistence

Loading...

Loading...

Loading...

Loading...

Optimization

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Connected entities

Loading...

Loading...

Loading...

Simulators

Loading...

Loading...

Loading...

Loading...

Tutorial project

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Game Services

Loading...

Loading...

Loading...

Developer Portal

Loading...

Loading...

Loading...

Loading...

Loading...

API reference

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Schema reference

Loading...

Loading...

Loading...

Loading...

Resources

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Community

Additional information

Loading...

Loading...

Loading...

Loading...

Requirements

Game Engine Support

coherence currently supports Unity. For custom engine integration, please contact our developer relations team. For updates regarding Unreal Engine support, please check the Unreal Engine support page.

Unity Requirements

  • Unity 2020.1.9f1 or later.

  • A Windows, Linux or Mac system.

The current version of coherence uses the Unity Entities package. Unity that they will not support this package in Unity 2021 for a while. This means that the current recommended Unity version for using coherence is Unity 2020 LTS. This is only temporary as we have been working on removing the reliance on Entities internally.

What is coherence?

Overview

coherence is a network engine, platform and a series of tools to help anyone create a multiplayer game.

  • Fast network engine with cloud scaling, state replication, persistence and auto load balancing.

Welcome

Games are better when we play together.

Get started

coherence is a network engine, platform and a series of tools to help anyone create a multiplayer game. Our mission is to give any game developer, regardless of how technical they are, the power to make a connected game.

Share builds

coherence allows you to upload and share the builds of your games to your team, friends or adoring fans via an eay access play link.

Right now we support desktop (PC, Mac, Linux) and also WebGL, where you can host and instantly play your multiplayer game and share it around the world.

Build the game

Build your game to a local folder on your desktop as you would normally.

In the coherence menu in Unity select "Share -> Build Upload"

How does coherence work?

Basic Terms

Replication Server ("Replicator")

A lean and performant server that keeps the state of the world and replicates it efficiently between various simulators and game clients. The Replicator usually runs in the

recently announced

Easy to develop, iterate and operate connected games and experiences.

  • SDK allows developers to make multiplayer games using Windows, Linux or Mac, targeting desktop, console, mobile, VR or the web.

  • Game engine plugins and visual tools will help even non-coders create and quickly iterate on a connected game idea.

  • Scalable from small games to large virtual worlds running on hundreds of servers.

  • Game-service features like user account, key-value stores and matchmaking.

  • Network Engine

    At the core of coherence lies a fast network engine based on bitstreams and a data-oriented architecture, with numerous optimization techniques like delta compression, quantization and network LOD-ing ("Level of Detail") to minimize bandwidth and maximize performance.

    Authority Models

    The network engine supports multiple authority models:

    • Client authority

    • Server authority

    • Server authority with client prediction

    • Authority handover (request, steal)

    • Distributed authority (multiple simulators with seamless transition)

    • Deterministic client prediction with rollback (""): coming in a future release

    Persistence

    coherence supports persistence out of the box.

    This means that the state of the world is preserved no matter if clients or simulators are connected to it or not. This way, you can create shared worlds where visitors have a lasting impact.

    Engine Support

    The coherence SDK only supports Unity at the moment. Unreal Engine support is planned. For more specific details and announcements, please check the Unreal Engine Support page. For custom engine integration, please contact our developer relations team.

    Tutorial project

    The Network Playground is a collection of scenes showing you how to use various features of the coherence Unity SDK. It shows you how to synchronize transforms, physics, persistence, animations, AI navigation and send network commands.

    Existing or new Unity project

    You can follow our step-by-step guide to learn how to install coherence in Unity, set up your scene, prefabs, interactions, as well as deploy your project to be shared with your friends.

    Join the community

    Join our community Discord for community chatter and support.

    • Join our official Developer Discord channel.

    • Contact us at [email protected]

    Get the Tutorial Project
    Install coherence
    Upload to coherence

    in this window you can select which platform the build is for an you also need to browse to the local path folder.

    Click "Upload" or "Begin Upload" and coherence will confirm that it's okay to compress and upload the build to the webdashboard.

    Share your build

    Now that build has been updated (signified by the green tick), you can share it by enabing and share the public URL. Anyone with this link can access the build.

    WebGL

    If you uploaded a WebGL build then you can play it instantly from that public link for instant play.

    coherence Cloud
    , but developers can start it locally from the command line or the Unity Editor.

    Game Client

    A build of the game. To connect to coherence, it will use the coherence SDK.

    Simulation Server ("Simulator")

    A version of the game client without the graphics ("headless client") optimized and configured to perform server-side simulation of the game world. When we say something is simulated on the server, we mean it is simulated on one or several simulators.

    Schema

    A text file defining the structure of the world from the network's point of view. The schema is shared between the replicators, simulators and game clients. The world is generally divided in components and archetypes.

    Code Generation

    The process of generating code specific to the game engine that takes care of network synchronization and other network-specific code. This is done using a CLI tool called Protocol Code Generator that takes the schema file and generates code for various engines (e.g. C# for Unity).

    State Replication

    The process of making sure the state of the world is eventually the same on the replicator, simulators and game clients, depending on their areas of interest.

    State Replication

    coherence works by sharing game world data via a Replication Server in the cloud and passing it to the connected clients.

    The clients and simulators can define areas of interest (LiveQueries), levels of detail, varying simulation and replication frequencies and other optimization techniques to control how much bandwidth and CPU power is used in different situations.

    The game world can be run using multiple simulators that split up simulation functions or areas of the world accordingly.

    Fast authority transfer and remote commands allow different authority models, including client authority, server authority, distributed authority and combinations like client prediction with input queues.

    The platform handles scaling, synchronization, persistence and load balancing automatically.

    Peer-to-peer support (without a replicator) is planned in a future release. Please see the Peer-to-peer page for updates.

    Deploy replication server

    Now we can finally deploy our schema and replication server into the cloud.

    Upload schemas

    In the Project Settings tab for coherence, click on Upload.

    The status should change from "Unknown" to "In Sync".

    If the status does not say In Sync, or if you encounter any other issues with the server interface, please refer to the section.

    Your project schema is now deployed with the correct version of the replication server already running in the cloud. You will be able to see this in your cloud dashboard status.

    Run project

    When you run the project now, you will notice that the Connect Dialog now contains additional address(-es). The Connect Dialog uses the to fetch all the addresses available for your project. This depends on the project configuration (e.g. the regions that you have selected for your project).

    You can now build the project again and send the build to your friends for testing.

    You will be able to play over the internet without worrying about firewalls and local network connections.

    Make sure everybody selects the remote server before clicking Connect.

    We are working on a WebGL / Webassembly option that will automatically upload the browser-playable build to your own personal webpage that you can share with your friends. For more information about our roadmap, please contact our .

    Build and run

    Now we can build the project and try out network replication locally.

    This example will show you how to launch a local and connect multiple instances.

    Running a Replication Server Locally

    You can run a local replication server from the coherence menu by clicking:

    coherence -> Server -> Run Local Server.

    Scene setup

    Setup Video Tutorial

    It's quick and easy to set up a networked scene from scratch using the coherence SDK. This example will show you the basic steps to sync up some moving characters.

    Add these components to your scene to prepare it for network synchronization.

    Create a free account

    Cloud Deploy Video Tutorial

    Now that we have tested our project locally, it's time to upload it to the cloud and share it with our friends and colleagues. To be able to do that, we need to create a free account with coherence.

    Features and Roadmap

    coherence is currently in private preview. Some stability and performance issues may still be present and being ironed out. Additionally, more features are planned for the public release later this year.

    Current features

    Install coherence

    Install Video Tutorial

    Unity Package Manager

    How authority works

    Networked entities can be simulated either on a game client ("client authority") or a simulation server ("server authority).

    Client Authority

    Client authority is the easiest to set up initially, but it has some drawbacks:

    • Higher latency. Because both clients have a non-zero ping to the replication server, the minimum latency for data replication and commands is the combined ping (client 1 to replications server and replication server to client 2).

    General
    • Custom UDP transport layer using bit streams with reliability

    • Smooth state replication

    • Server-side, client-side, distributed authority

    • Connected entity support

    • Fast authority transfer

    • Remote messaging (RPC)

    • Persistence

    • Multiple examples and showcases

    • Verified support for Windows, macOS, Linux, Android, iOS and WebGL

    SDK

    • Unity SDK with intuitive no-code layer

    • Per-field adjustable interpolation and extrapolation

    • Input queues

    • Easy deployment into the cloud

    • SDK source included, no 3rd-party libraries

    Optimization and performance

    • Per-field compression and quantization

    • Per-field sampling frequency adjustable at runtime

    • Unlimited per-field levels of detail

    • Areas of interest

    • Accurate SimulationFrame tracking

    Online

    • Developer portal with server and service configurator

    • Multiple regions (US East, EU Central)

    • Player accounts

    • Key-value store

    • Matchmaking

    • Ability to deploy one replication server and one simulation server per environment

    • Prometheus and Grafana integration

    Coming soon

    SDK

    • Support for lean pure C# clients and simulators without Unity

    • Faster input queues

    • Network Profiler

    Online

    • Additional regions

    • Support for multiple simulators and replicators in a single project

    • Dashboard with usage statistics

    Mid-term roadmap

    • Peer-to-peer (without replication server) with NAT punch-through

    • TCP fallback support

    • WebSockets support

    • MTU detection

    • Packet replay

    • Ability to deploy multiple simulation servers per environment

    • Player analytics

    • Additional packet compression

    • Developer portal graphs and analytics

    • Simulator authentication

    Roadmap

    • JavaScript SDK

    • Unreal Engine SDK

    • Multiple replication servers per game world

    • Customer-specific serialization

    • User-space load-balancing (SDK framework)

    • Game world map with admin interface

    • Anti-cheat functionality

    • Advanced transaction logs (audit trail)

    • Schema versioning (hot updates)

  • Higher exposure to cheating. Because we trust game clients to simulate their own entities, there is a risk that one such client is tampered with and sends out unrealistic data.

  • In many cases, especially when not working on a competitive PvP game, these are not really issues and are a perfectly fine choice for the game developer.

    Client authority does have a few advantages:

    • Easier to set up. No client vs. server logic separation in the code, no building and uploading of simulation servers, everything just works out of the box.

    • Cheaper. Depending on how optimized the simulator code is, running a simulator in the cloud will in most cases incur more costs than just running a replication server (which is comparatively very lean).

    Server Authority

    Having one or several simulators taking care of the important world simulation tasks (like AI, player character state, score, health, etc.) is always a good idea for competitive PvP games.

    Running a simulator in the cloud next to the replicator (the ping between them being negligible) will also result in lower latency.

    The player character can also be simulated on the server, with the client locally predicting its state based on inputs. You can read more about how to achieve that in the section input queues.

    Peer-to-peer support (without a replicator) is planned in a future release. Please see the Peer-to-peer page for updates.

    Remote Communication

    Even if an entity is not currently being simulated locally, we can still affect its state by sending a network command or even requesting a transfer of authority.

    GGPO

    Extrapolation

    Extrapolation or "dead reckoning" uses historical data to predict the future state of a component. The actual network data that arrives later can be used to interpolate or snap the predicted values to the correct ones.

    We will be adding an example of extrapolation in a subsequent release.

    Overview

    Sometimes you want to synchronize entities that are connected to other entities. These relationships can be references between entities, but they can also involve direct parent-child relationship between game objects, or more nuanced use cases.

    Here's a guide for what technique to use, depending on the situation:

    • If you have an entity that needs to keep a nullable reference to another entity, use a normal Entity reference. This includes any existing MonoBehaviour that has GameObject or Transform fields that you want to synchronize over the network.

    • If the entities are placed in a hierarchy, use the techniques for parent-child relationships.

    Downloads

    coherence Network Playground Unity Project Zip

    coherence Network Playground (Unity Version 2020.3.13f1 or later)

    Archetype

    Refer to the Level of detail section for more information.

    Troubleshooting

    Coming soon.

    This will open a new terminal window with the replication server.

    Build and Connect

    Now it's time to make a standalone build and test network replication.

    #protip: Go to Project Settings, Player and change the Fullscreen Mode to Windowed and enable Resizable Window. This will make it much easier to observe standalone builds side-by-side when testing networking.

    Open the Build Settings window (File -> Build Settings). Click on Add Open Scenes to add the current scene to the build. Click Build and Run.

    Select a folder (e.g. builds) and click OK.

    When the build is done, start another instance of the executable (or run the project in the Game Window in Unity).

    Click Connect on both clients. Now try focusing one and using WSAD keys. You will see the box move on the other side as well.

    Congratulations, you've made your first coherence replicated experience. But this is only the beginning. Keep reading to take advantage more advanced coherence features.

    Connect across the local network

    If you want to connect to the local replication server from another local device (such as another PC, Mac, Mobile or VR device), you can find your IPv4 address and use that as your server address in the Connect dialog. These devices need to be connected to the same network.

    You can find your IPv4 address by going to your command line tool and type ipconfig . Remember to include the port number, for example 192.168.1.185:32001.

    Make sure your Firewall allows remote connections to connect to the replication server from other devices on your network.

    replication server
    1. Add MonoBridge

    coherence -> Scene Setup -> Create MonoBridge

    This object takes care of connected GameObject lifetimes and allows us to develop using traditional MonoBehaviour scripts.

    2. Add LiveQuery - Hierarchy

    coherence -> Scene Setup -> Create LiveQuery

    Creates a LiveQuery which queries the area around the local player to get required information from the replication server. You can surround your entire scene in one query or can attach it to an object such as the player or a camera.

    Set the radius of the LiveQuery

    3. Add the Sample UI

    coherence -> Scene Setup -> Add Sample UI

    Creates a Canvas (and Event System if not already present in the scene) with a sample UI that helps you connect to a local or remote replication server. You can create your own connection dialog, this one is just a quick way to get started.

    Sign up or log in

    In your web browser, navigate to https://dev.coherence.io.

    Create an account or log into an existing one.

    Create an organization

    Create an organization.

    Create project

    Under the organization, create a new project.

    Get portal token

    Open the project dashboard and find the Portal token.

    Copy the token to your clipboard.

    Copy Portal token into Unity

    Open Unity and navigate to the Project Settings. Open the coherence tab.

    Paste the token into the Portal Token section.

    Fetch the Runtime key

    Once you have pasted the portal token successfully, you need to fetch the runtime token as well.

    You can fetch the Runtime key by clicking on the down-arrow button on the right side of the input field.

    coherence only supports Unity at the moment. Unreal Engine support is planned. For more specific details and announcements, please check the Unreal Engine Support page. For custom engine integration, please contact our developer relations team.

    1. Add a scoped registry

    First, open Project Settings.

    Under Package Manager, add a new Scoped Registry with the following fields:

    • Name: coherence

    • URL: https://registry.npmjs.org

    • Scope(s): io.coherence.sdk

    • Enable Preview Packages: checked

    • Show Dependencies: checked

    Click Apply.

    2. Find and install the coherence package

    Now open the Package Manager.

    Click Packages and My Registries.

    Under coherence, click Install.

    Alternative Method: Edit manifest.json manually

    If you want to install coherence manually, go to the folder of your project and open the file /Packages/manifest.json.

    Copy paste the lines surrounded by comments that look like this:/* comment */.

    The Unity docs have information about scoped package registries.

    When you install the coherence Unity Package, all the services for the SDK are installed in the background as well.

    You will then see this package in the Package Manager under "My Registries".

    The coherence SDK has some dependencies on other Unity packages you can see in the image above. If you're already using these in your project, you might have to adjust their version number (Unity will tell you about this).

    When you successfully install the coherence SDK you'll get this quickstart window pop-up and you'll be good to go.

    troubleshooting
    runtime key
    developer relations team

    Baking and code generation

    Baking Video Tutorial

    Overview

    Out of the box, coherence will use C# Reflection to sync all the data at runtime. This is a great way to get started but it is very costly performance-wise.

    For optimal runtime performance, we need to create a schema and perform code generation specific to our project. Learn more about this in the section.

    coherence offers an automatic way of doing that called baking.

    Bake schemas

    Click on coherence -> Schema and Baking -> Bake Schemas.

    This will go through all CoherenceSync components in the project and generate a schema file based on the selected variables, commands and other settings. It will also take into account any CoherenceArchetype components.

    For every prefab with a CoherenceSync object, the baking process will generate a bespoke C# file in the coherence/baked folder in the project.

    Adding that file to the prefab will make that prefab use bespoke generated code instead of C# reflection.

    Activate baked schema on prefab

    Once the Schema has been baked, you will be able to switch to baked mode in the CoherenceSync inspector.

    The name of the baked script will be CoherenceSync[prefabName].

    Modifying bound data, safe mode and the watchdog

    When you bind to your script's fields and bake, coherence generates specific code that accesses your code directly, without using reflection. This means, whenever you change your scripts, you might break compilation.

    For example, if you have a Health.cs script which exposes a public float health; field, and you mark health as a binding in the Bindings window, the baked script will access your component via type name, and your field via field name.

    Your baked script might now reference your component:

    Baked scripts reside by default in Assets/coherence/baked, but you can check where exactly they're located in the settings window.

    This means that if you decide to change your component name (Health) or your any of your bound field names (health), Unity script recompilation will fail. In this example, we will be deprecating health and adding health2 in its place.

    Our watchdog is able to understand when this happens, and offer you a solution right away.

    It will suggest you to bake in safe mode, and then diagnose the state of your prefabs. After a few seconds of script recompilation, you'll be presented with the diagnosis window.

    You can enter safe mode manually via coherence > Schema and Baking > Bake Schemas (Safe Mode).

    In this window, you can easily spot bindings in your prefabs that are no longer valid. In our example, health is no longer valid since we've moved it elsewhere (or deleted it).

    Click on the hand pointing button to open the bindings window, and take a look at your script:

    Now, we can manually rebind our data: unbind health and bind health2. Once we do, we can now safely bake again.

    Baking in safe mode creates scripts that will help avoid compilation errors, but prefabs that use these will not work in runtime. Remember to bake again normally when you're done fixing your prefabs.

    Configuring persistence

    CoherenceSync configuration

    The CoherenceSync editor interface allows us to define the Lifetime of a networked object. The following options are available:

    • Session Based. No persistence. The entity will disappear when the client or simulator disconnects.

    • Persistent. The entity will remain on the server until a simulating client deletes it.

    Persistence UUID

    Persistent objects need to be identified so that the system can know how to treat duplicate persistent objects.

    Manually assigning a UUID means that each instance of this persistent object prefab is considered the same object regardless of where on the network it is instantiated. So, for example, if two clients instantiate the same prefab object with the same persistence UUID then only one is considered official and the other is replaced by the replication server.

    Deleting a persistent object

    A persistent object can be deleted only by the client or simulator that has authority over it. For indirect remote deletion, see the section about .

    Deleting a persistent object is done the same as with any network object - by destroying its GameObject.

    Overview

    Bandwidth is limited

    No matter how fast the internet becomes, conserving bandwidth will always be important. Some game clients might be on poor mobile networks with low upload and download speeds, or have high ping to the replication server and/or other clients, etc.

    Additionally, sending more data than is required consumes more memory and unnecessarily burdens the CPU and potentially GPU, which could add to performance issues, and even to quicker battery drainage.

    Optimization techniques

    In order to optimize the data we are sending over the network, we can employ various techniques built into the core of coherence.

    • Delta-compression (automatic). When possible, only send differences in data, not the entire state every frame.

    • Compression and quantization (automatic and configurable). Various data types can be compressed to consume less bandwidth that they naturally would.

    • Simulation frequency (configurable). Most entities do not need to be simulated at 60+ frames per second.

    World size

    Why does world size matter?

    Positions and livequeries in the world are compressed, and the compression is defined by maximum scale and bit count. Larger scale at the same bit count means lower precision, and vice-versa.

    Defining world size

    A default maximum world size of 2400 means that only values from [-2400, 2400] will be supported for all spatial axes.

    If our game scenes are larger than 2400 x 2 (4800) units across, we can increase this value in the Settings window or in the schema as illustrated below.

    Don't forget to extend the LiveQuery scale to match the world position scale.

    Storage

    Persistence in memory

    All persistent objects remain in the world for the entire lifetime of the replication server. But what happens when the replication server is restarted or goes offline?

    Persistence Client

    Persistence Client is a special utility that runs alongside the replication server and records the state of the world and saves it to physical storage. If the replication server goes offline, the Persistence Client will backup the entire state of the world.

    The Persistence Client will be available as part of the coherence online services in a future release. Please contact our for more information.

    7. Network Teams (draft)

    General Set up

    In the Hierarchy of the Scene you can see three core Prefabs:

    Core Scene Setup and Coherence Setup are present in all scenes and described in detail on page.

    Coherence Entity is the prefab that will change per Scene with different functionality. It has a standard CharacterControllerand Rigidbody as well as an Agent script which will handle movement functionality through the Input Manager in the Core Scene Setup prefab.

    In This Scene...

    Build and Try

    You can build this Scene via the Build Settings. Run the local Replication Server through the Window -> coherence -> Settings window and see how it works. You can try running multiple clients rather than just two and see replicating for each.

    MonoBridge

    The MonoBridge is a system that makes sure every GameObject is linked to its networked representation. It essentially interfaces between the GameObject world and the DOTS/ECS-based coherence SDK code running "under the hood".

    Note: All of this code is accessible to you and can be interfaced with directly using DOTS.

    When you place a GameObject in your scene, the MonoBridge detects it and makes sure all the synchronization can be done via the CoherenceSync component.

    Video Tutorials

    Authority transfer

    Overview

    The state of network entities that are currently not simulated locally (either because they are being simulated on another game client or on a simulator) cannot be affected directly.

    Network can help us affect state indirectly, but for anything more involved, an authority transfer might be necessary.

    Overview

    Persistent vs. session-based entities

    When we connect to a game world with a game client, the traditional approach is that all entities originating on our client are session-based. This means that when the client disconnects, they will disappear from the network world for all players.

    A persistent object, however, will remain on the replication server even when the client or simulator that created or last simulated it, is gone.

    This allows us to create a living world where player actions leave lasting effects.

    In a virtual world, examples of persistent objects are:

    Simulation frequency

    If we don't do any special configuration, entity data is captured at the highest possible frequency and sent to the replication server. This often generates more data than is needed to efficiently replicate the entity's state across the network.

    Global simulator frequency

    On a simulator, we can limit the framerate globally using Unity's built-in static variable targetFrameRate.

    Areas of interest

    LiveQuery

    The way you get information about the world is through LiveQueries. We set criteria for what part of the world we are interested in at each given moment. That way, the replicator won’t send information about everything that is going on in the game world everywhere, at all times.

    Instead, we will just get information about what’s within a certain area, kind of like moving a torch around to look in a dark cave.

    Overview

    What is the Developer Portal?

    The developer portal is an online dashboard where the cloud services behind your coherence-based game can be managed. It can be found at or from the Developer Portal link above.

    The developer portal includes:

    4. Animation and Variables

    Animation & Variables

    This scene will show you how easy it is to set up Networking in your Unity project and sync GameObject transforms, animations via the Animator parameters and customer variables.

    In this example, each client will have its own player character to move, the beloved Unity RobotKyle asset. Type your name into the connect dialog box and connect. You can move around with WASD. When another player connects, their name is carried across and their transform and animation state is replicated.

    Get the Tutorial Project

    coherence only supports Unity at the moment. Unreal Engine support is planned. For more specific details and announcements, please check the page. For custom engine integration,.

    Network Playground Project

    Cloud API

    List of the Cloud APIs

    Overview

    The coherence Cloud API allows us to access online services like game accounts, key-value store, matchmaking, and others. It also allows you to get the addresses (IP and port number) of the servers the players can connect to.

    The Cloud API requires you to use.

    Server discovery

    Here is a sample script showing how you can use the server discovery API to get the servers associated with your runtime key.

    Enabling Game Services

    Besides the core replicator and simulator, coherence offers additional services to enhance your game's experience and we are constantly working on more.

    Currently available services are:

    Game account

    Motivation

    coherence provides an API for creating player game accounts that uniquely identify players across multiple devices. An account is required in order to use the rest of the online services, like the key-value store and matchmaking.

    Dashboard

    After creating an Organization and Project, (see ), your Developer Portal home page will be the Dashboard.

    Here you can find:

    • Your Portal token

    • The status of your replication, simulation, and persistence resources

    1. Transforms

    Transforms

    Welcome to the first scene of the coherence Network Playground. This scene will show you how easy it is to set up networking in your Unity project and sync GameObject transforms across the network.

    In this example, each client will have a player character to move by clicking on the map to make the entity move to that location. Each client will only have control of its local entity.

    6. Network Commands

    Sending Network Commands

    This scene will show you how easy it is to set up Networking in your Unity project and send Network Commands to other clients. Network Commands is like sending a direct message to another player, without anyone else knowing.

    In this example each client has one character they can control with click to move input. They can right-click on another Entity to send a command and that Entity will instantiate an Exclamation mark above their head.

    Matchmaking

    Motivation

    coherence provides a powerful matchmaking API with various different setups (multiple teams, team sizes, etc.).

    Configuration

    Pricing

    We are currently preparing a fair and affordable pricing model in line with our philosophy of fairness and supporting low-risk iterative game development.

    For more information, please check back later or contact our .

    Parent-child relationships

    Overview

    Objects with the CoherenceSync component can be connected to other CoherenceSync components with a parent-child relationship. For example, an object can be linked to a hand, a hand to an arm, and the arm to a spine.

    Resource Usage

    Resource Usage is a work in progress and may not represent full or accurate usage during developer alpha.

    Currently, resource usage resides on the Dashboard. A dedicated Resource Usage to help understand your costs and usage is coming soon.

    • Replicator - the CPU/Memory and Bandwidth usage of your replication servers per region

    WebGL

    This page is WIP

    For anyone building WebGL in Linux: you need to install these packages: sudo apt install clang libtinfo5 python python-setuptools

    For running a WebGL build locally, please refer to the .

    SLA

    For information about our SLA options, please check back later or contact our .

    {
      "dependencies": {
        "com.unity.collab-proxy": "1.3.9",
        "com.unity.ide.rider": "2.0.7",
        "com.unity.ide.visualstudio": "2.0.7",
        "com.unity.ide.vscode": "1.2.3",
        "com.unity.test-framework": "1.1.24",
        "com.unity.textmeshpro": "3.0.1",
        "com.unity.timeline": "1.4.6",
        "com.unity.ugui": "1.0.0",
    
        /*** ADD THIS START ***/
        "io.coherence.sdk": "0.5.2",
        /*** ADD THIS END ***/
            
        "com.unity.modules.ai": "1.0.0",
        "com.unity.modules.androidjni": "1.0.0",
        "com.unity.modules.animation": "1.0.0",
        "com.unity.modules.assetbundle": "1.0.0",
        "com.unity.modules.audio": "1.0.0",
        "com.unity.modules.cloth": "1.0.0",
        "com.unity.modules.director": "1.0.0",
        "com.unity.modules.imageconversion": "1.0.0",
        "com.unity.modules.imgui": "1.0.0",
        "com.unity.modules.jsonserialize": "1.0.0",
        "com.unity.modules.particlesystem": "1.0.0",
        "com.unity.modules.physics": "1.0.0",
        "com.unity.modules.physics2d": "1.0.0",
        "com.unity.modules.screencapture": "1.0.0",
        "com.unity.modules.terrain": "1.0.0",
        "com.unity.modules.terrainphysics": "1.0.0",
        "com.unity.modules.tilemap": "1.0.0",
        "com.unity.modules.ui": "1.0.0",
        "com.unity.modules.uielements": "1.0.0",
        "com.unity.modules.umbra": "1.0.0",
        "com.unity.modules.unityanalytics": "1.0.0",
        "com.unity.modules.unitywebrequest": "1.0.0",
        "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
        "com.unity.modules.unitywebrequestaudio": "1.0.0",
        "com.unity.modules.unitywebrequesttexture": "1.0.0",
        "com.unity.modules.unitywebrequestwww": "1.0.0",
        "com.unity.modules.vehicles": "1.0.0",
        "com.unity.modules.video": "1.0.0",
        "com.unity.modules.vr": "1.0.0",
        "com.unity.modules.wind": "1.0.0",
        "com.unity.modules.xr": "1.0.0"
      }, /* add this comma if not already present */
      
      /*** ADD THIS SECTION START ***/
      "scopedRegistries": [
        {
          "name": "coherence",
          "url": "https://registry.npmjs.org",
          "scopes": [
            "io.coherence.sdk"
          ]
        }
      ]
      /*** ADD THIS SECTION END ***/
      
    }
    
  • A door anyone can open, close or lock

  • User-generated or user-configured objects left in the world to be found by others

  • Game progress objects (e.g. in PvE games)

  • Voice or video messages left by users

  • NPC's wandering around the world using an AI logic

  • Player characters on "auto pilot" that continue affecting the world when the player is offline

  • And many, many more

  • A persistent object with no simulator is called an orphan. Orphans can be configured to be auto-adopted by clients or simulators on a FCFS basis.

    Account Types

    There are two types of accounts that are currently supported - guest accounts and user accounts.

    Guest Accounts

    Guest accounts provide an easy way to start using the coherence online services without providing any user interface for user names or password. Everything is controlled with the API, and is completely transparent to the player.

    The session data for the account is stored locally on the device so it is important to know that uninstalling the game will also wipe out all the data and the account will be no longer accessible even if the player installs the game again.

    User Accounts

    User accounts require explicit authorization by the player. Currently, only user name and password are supported as means for authentication. The user interface for entering the credentials must be provided by the game. Check the API how to use this feature.

    In the future, there will be support for many more authentication mechanisms like Steam, Google Play Games, Sign in with Apple, etc.

    Using game accounts

    Please refer to the Cloud API: Game Accounts.

    When and object has a parent in the network hierarchy, its transform (position and orientation) will update in local space, which means its transform is relative to the parent's transform.

    A child object will only be visible in a LiveQuery if its parent is within the query's boundaries.

    Usage

    Creating an entity hierarchy is very simple. All you need to do is to add a GameObject with a CoherenceSynccomponent as a direct child of another GameObject with a CoherenceSynccomponent. You can add and remove parent-child relationships at runtime (even from the editor).

    Hierarchies with intermediary transforms

    Sometimes, it is not practical to add CoherenceSyncobjects to all the links in the chain. For example, if a weapon is parented to a hand controlled by an Animator, we do not need to synchronize the entire skeleton over the network. We will provide a helper script for such cases.

    developer relations team
    Start Tutorial
    Organization and Project creation and management
  • Resource configuration and management

  • Enabling / disabling features

  • Cost analysis

  • Team management

  • Here are some examples of tasks to perform on the developer portal:

    • Create your organization and project for your game

    • Start/stop/restart your cloud-based replication server or simulator

    • Enable coherence features such as player authentication, key-value store, persistence, and build sharing

    • Invite teammates to your project

    • View your resource usage and billing forecasts

    Is the Developer Portal required for development?

    While a local replication server is available as part of the Unity SDK, in order host the multiplayer services like the replication server in the cloud, your team must have a project in the Developer Portal. It is up to your project needs when to begin using the cloud services.

    Getting started

    Please see the page, Create a free account, in the Get Started section.

    https://dev.coherence.io
    List of endpoints
    • Server discovery

    • Game account

    • Key-value store

    • Matchmaking

    tokens connected to your coherence project
    developer relations team
    official Unity documentation
    developer relations team

    Glossary

    Archetype

    Group of Components that define a type. Makes use of LODs.

    Client

    Allows a User to interact with the World. Connects to Replication Server.

    Client connection​

    An object representing a client connected to the Replication Server. Required for the client messages.

    Client message​

    A message sent to a client connection.

    Command

    Allows for sending an instruction to an Entity that may be running on a different machine.

    Component

    Part of ECS. Describes a characteristic or aspect of an Entity.

    ECS

    Stands for Entity Component System. An entity system where entities are made of components.

    Entity

    An instance of an Archetype. Part of ECS.

    Live Query

    Allows the Client to specify a subset of the World to receive updates from. Acts as a filter to exclude updates on less relevant entities that could otherwise result in undesired latency.

    LOD

    A partial representation of an Archetype. Allows for specifying priorities of components within an Archetype.

    Protocol Code Generator

    Generates the client schema source file (e.g. schema.cs) that automatically handles serialization/deserialization of an ECS world and commands.

    Replication Server

    Replicates the state of the world to the connected Clients and Simulators.

    Simulator

    Responsible for simulating a subset of the game world. Connects to Replication Server through which the state gets replicated to Clients.

    Unreal Engine support

    Unreal Engine support is planned for a future release of coherence.

    Check back here for more news or contact [email protected] for more information or collaboration options.

    You can also join our Discord to get in touch with the team directly.

    // Initialize network API
    Network.Init(RuntimeSettings.instance.playToken);
    
    // Get the list of servers associated with the token
    var network = World.DefaultGameObjectInjectionWorld.GetExistingSystem<NetworkSystem>();
    if (network.ConnectionAddresses != null)
    {
        foreach (var connection in network.ConnectionAddresses)
        {
            serverDropdown.options.Add(new Dropdown.OptionData
            {
                text = string.Format("{0} {1}:{2}", connection.region, connection.ip, connection.port)
            });
        }
        serverDropdown.value = serverDropdown.options.Count - 1;
    }
    coherence will automatically limit the target framerate of uploaded simulators to 30 frames per second. We plan to enable lifting this restriction in the future. Check back for updates in the next couple of releases.

    Per-component frequency limitation

    Components can have their own maximum simulation framerates. These can be defined at runtime by adding a Set[ComponentName]Frequency component to the entity.

    In the future, you will be able to define entity simulation frequencies in the schema as well.

    Application.targetFrameRate = 10;
    var entity = coherenceSync.LinkedEntity;
    
    if(entity != Entity.Null)
    {
        EntityManager.AddComponentData(entity, 
            new SetWorldPositionFrequency 
            { 
                samplingFrequency = 3.0f 
            }
        );
    }
    Levels of detail (configurable). Entities need to consume less and less bandwidth the farther away they move from the observer.
  • Area of interest. Only replicate what we can see.

  • Types of Authority Transfer

    In the design phase, CoherenceSync objects can be configured to handle authority transfer in different ways:

    • Request. Authority transfer may be requested, but it may be rejected by the receiving party (i.e. when Approve requests is false).

    • Steal. Authority will always be given to the requesting party on a FCFS ("first come first serve") basis.

    • Not transferable. Authority cannot be transferred.

    If you uncheck the Approve Requests, you can use the unity event OnAuthorityRequested to respond to the request.

    The request can be approved or rejected in the callback.

    Requesting Authority in Code

    Requesting authority is very straight-forward.

    As the transfer is asynchronous, we have to subscribe to one or more Unity Events in CoherenceSync to learn the result.

    The request will first go to the replication server and be passed onto the receiving simulator or game client, so it may take a few frames to get a response.

    These events are also exposed to the Unity inspector in the Events on authority transfer section of the CoherenceSync behaviour.

    Authority events in the CoherenceSync inspector
    commands
    More complex area of interest types are coming in future versions of coherence.

    Adding a LiveQuery to the scene

    A LiveQuery is a cube that defined the area of interested in a particular part of the world. It is defined by its position and its radius (half the side of the cube). There can be multiple LiveQueries in a single scene.

    Moving a LiveQuery

    A classic approach is to put a LiveQuery on the camera and set the radius to correspond to the far clipping plane or visibility distance.

    Moving the GameObject containing the LiveQuery will also notify the replication server that the query for that particular game client has moved.

    General Set Up

    In the Hierarchy of the scene you can see the two core prefabs Core Scene Setup and Coherence Setup. Both are present in all scenes and described in detail on Start Tutorial page.

    In This Scene...

    Coherence Kyle is taken from the Unity asset "Robot Kyle", with added components Rigidbody, Character Controller, and Animator with the two animation states - Idle and Walk. The animation states are controlled by a speed parameter from the Agent script. The scene also contains a Name Badge script which gets the Connect Dialog GameObject from the Core Scene Setup and sets the color depending if it's local or networked.

    Attached to Coherence Kyle is a coherenceSync component which replicates the parametersTransform; position and rotation, Animator; Speed[float] and NameBadge; Name [string]. The authority and persistence settings are set to their default values and the On Network Instantiation event is used to change the color of the networked entities.

    Build and Try

    You can build this Scene via the Build Settings. Run the local Replication Server through the Window -> coherence -> Settings window and see how it works. You can try running multiple clients rather than just two and see replicating for each.

    You can read more about synchronizing animations on the Animations section.

    The Network Playground is a starter project for you to dive into. It contains the latest SDK, all the required preview packages and a bunch of extra resources for you to learn how to make multiplayer games with coherence.

    Download the Network Playground Unity Project

    You will need Unity Version 2020.3.13f1 or later.

    Download the Network Playground Project here.

    Network Playground Scenes

    Each Scene in this Network Playground Project shows you something new:

    • Scene 1. Synchronizing Transforms

    • Scene 2. Physics

    • Scene 3. Persistence

    • Scene 4. Synchronizing Animations and Custom Variables

    • Scene 5. AI Navigation

    • Scene 6. Network Commands

    • Scene 7. Teams.

    Unreal Engine Support
    please contact our developer relations team

    Matchmaking

    Enabling Game Services

    In the Project sidebar, you can find links to each service. Each service has an enabled checkbox which you can toggle to enable and disable those features:

    Note: Disabling a service will immediately remove that functionality from your game. Please disable with caution.

    Game account
    Key Value Store
    A high level view of your resource usage

    Resource Status

    Resource statuses and controls

    Replicator

    When you upload your schemas from the Unity SDK, coherence automatically starts a replication server in the cloud for your project.

    Possible states:

    • Pending upload - before the first time you upload your schemas from the Unity SDK

    • Running - your replicator is successfully running in the cloud. The coherence engine version used will also be listed

    • Stopped - your replicator has been manually stopped

    Simulator

    You must first have a running replicator and have enabled simulator services in the dashboard. See Enabling the Simulator.

    When you build and upload your simulator from the Unity SDK, coherence automatically starts a simulator server in the cloud for your project.‌

    Possible states:‌

    • Pending upload - before the first time you upload your simulator from the Unity SDK

    • Running - your simulator is successfully running in the cloud. The coherence engine version used will also be listed

    • Stopped - your replicator has been manually stopped

    Create a free account
    General Set Up

    In the Hierarchy of the Scene you can see three core Prefabs.

    Core Scene Setup and Coherence Setup are present in all (Network Playground) Scenes and described in detail on Start Tutorial page.

    Coherence Entity Character is the Prefab that will change per Scene with different functionality. It has a standard CharacterControllerand Rigidbody as well as an Agent script which will handle movement through the Input Manager in the Core Scene Setup prefab.

    In This Scene...

    Coherence Entity Character (always change the prefab, not the instance) is located in the Resources folder. The UnityEngine.Transform and position are ticked to sync. All other settings (persistence and authority) use the default settings. This entity will be session based, no authority handover and no adoption will take place, when a client leaves.

    The On Network Instantiation event is used to change the color of the mesh and recalculate the RigidBody collisions. That's it.

    Build and Try

    You can build this Scene via the Build Settings. Run the local Replication Server through the Window -> coherence -> Settings window and see how it works. You can try running multiple clients rather than just two and see replicating for each.

    General Set Up

    In the Hierarchy of the Scene you can see three core Prefabs:

    Core Scene Setup and Coherence Setup are present in all scenes and described in detail on Start Tutorial page.

    Coherence Entity is the prefab that will change per Scene with different functionality. It has a standard CharacterControllerand Rigidbody as well as an Agent script which will handle movement functionality through the Input Manager in the Core Scene Setup prefab.

    In This Scene...

    Coherence Entity can send commands to other entities through the Coherence Handler component. In the coherenceSync component, small "lightning bolt" icons are displayed next to the tick boxes for the syncable properties. These icons signify that they are public methods rather than singular variables and that these methods can be called through the Coherence Handler Event System, either to send or receive commands.

    In the game view in Play mode, Commands can be sent to other entities via the right click button. An exclamation mark asset should pop up above the right-clicked entity, but only for the sending and the receiving client. No other clients will be made aware of this.

    Build and Try

    You can build this Scene via the Build Settings. Run the local Replication Server through the Window -> coherence -> Settings window and see how it works. You can try running multiple clients rather than just two and see replicating for each.

    Before using the matchmaking service you have to configure it on the developer portal. Currently there are two things to setup: the timeout and the teams.

    The timeout is in seconds. There can be any number of teams and any number of players per team.

    For example, a chess game would need only one team with two players, while in a socker game you'd need two teams with eleven players per team.

    Using the matchmaking

    Please refer to the Cloud API: Matchmaking.

    Connections - the running total of connections from players to your Replication server

    How does coherence work
    Destroy(coherenceSync.gameObject);
    network commands
    CoherenceSync inspector
    # Default world positions:
    
    component WorldPosition
      value Vector3 [bits "24", scale "5000"]
      
    
    # LiveQuery:
    
    component WorldPositionQuery
      position Vector3 [bits "24", scale "5000"]
      radius Float [bits "24", scale "5000"]
    Settings window

    3. Persistence

    Physics & Persistence

    This scene will show you how easy it is to set up Networking in your Unity project and sync GameObject transforms and Physics objects across the network whilst keeping them persistent. As long as the server is running you can disconnect and re-connect, your world will persist.

    In this example each client will have it's own player character to move, we will click on the map to make the entity move to that location, simple click to move functionality and right click to spawn local physics based objects that all other player characters can interact with. Each client will only have control of its local entity. You can disconnect and re-connect and the persistent entities will all remain.

    General Set Up

    In the Hierarchy of the Scene you can see three core Prefabs:

    Core Scene Setup and Coherence Setup are present in all scenes and described in detail on page.

    Coherence Entity is the prefab that will change per Scene with different functionality. It has a standard CharacterControllerand Rigidbody as well as an Agent script which will handle movement functionality through the Input Manager in the Core Scene Setup prefab.

    Coherence Connection Events handles overall Scene connectivity. Additionally, it removes all Entities with coherenceSync from the Scene to demo disconnection/reconnection via the Interface without refreshing the Scene.

    In This Scene...

    The Physics Entity Spawner component is a simple script to instantiate a Coherence Entity Physics Persistent prefab with a coherenceSync component that replicates the transform and position. The component also changes the material based on if it is locally simulated or synced over the network.

    Coherence Entity Physics Persistent has Entity Lifetime Type set to Persistent. This means it will remain in the world as long as the replication server is running, even if all clients disconnect. It also has Authority Transfer Style set to Stealing which means the entity can be "stolen" and simulated on a client requesting authority.

    The Auto Generate Persistance UUID should be checked so that a unique identification string will be used to identify instances of this entity as unique. When the entity is spawned with this checked, it will generate its own UUID.

    This is done via the Input Manager in the Core Scene Setup prefab. When the object is left-clicked, it sends the message "Adopt" to the GameObject on the specific Layer Mask "Physics Entities". The component called Coherence Handler on Coherence Entity Physics Persistent handles the Adopt call and requests the authority change via the coherenceSync component.

    Coherence Handler is a basic layer for handling Commands and Events, both sending and receiving. You can create your own or reuse and extend this for your project.

    Build and Try

    You can build this Scene via the Build Settings. Run the local Replication Server through the Window -> coherence -> Settings window and see how it works. You can try running multiple clients rather than just two and see replicating for each.

    2. Physics

    Physics

    This scene will show you how to use coherence to sync GameObject transforms and Physics objects across the network.

    In this example, each client will have its own player character to move. Left-clicking on the map will make the entity move to that location. Right-clicking will spawn local physics based objects that all player characters can interact with. Each client will only have control over its local entity.

    General Set Up

    In the Hierarchy of the Scene you can see three core Prefabs:

    Core Scene Setup and Coherence Setup are present in all scenes and described in detail on page.

    Coherence Entity is the prefab that will change per Scene with different functionality. It has a standard CharacterControllerand Rigidbody as well as an Agent script which will handle movement functionality through the Input Manager in the Core Scene Setup prefab.

    Coherence Connection Events handles overall Scene connectivity. Additionally, it removes all Entities with coherenceSync from the Scene to demo disconnection/reconnection via the Interface without refreshing the Scene.

    In This Scene...

    Coherence Entity Character (always change the prefab, not the instance) is located in the Resources folder. The UnityEngine.Transform and position are ticked to sync. All other settings (persistence and authority) use the default settings. This entity will be session based, no authority handover and no adoption will take place, when a client leaves.

    The On Network Instantiation event is used to change the colour of the mesh.

    The Physics Entity Spawner is a simple script to instantiate a Coherence Entity Physics Prefab with a coherenceSync component that replicates the transform and position. The component also changes the material based on if it is locally simulated or synced over the network.

    Build and Try

    You can build this Scene via the Build Settings. Run the local Replication Server through the Window -> coherence -> Settings window and see how it works. You can try running multiple clients rather than just two and see replicating for each.

    5. AI Navigation

    AI Navigation, Session Based NPC's

    This scene will show you how easy it is to set up Networking in your Unity project and sync non player characters that move around the world via Unity's Navmesh system.

    In this example each client can spawn as many navigation agents as they wish, and these navigation agents will move intermittently to different locations on the grid. All navigation agents will be replicated across clients with a specific colors signifying if they are local or networked.

    General Set Up

    In the Hierarchy of the Scene you can see three core Prefabs:

    Core Scene Setup and Coherence Setup are present in all scenes and described in detail on page.

    Coherence Connection Events handles overall Scene connectivity. Additionally, it removes all Entities with coherenceSync from the Scene to demo disconnection/reconnection via the Interface without refreshing the Scene.

    In This Scene...

    Spawner is a simple script to instantiate a Coherence Entity Nav Agent prefab with a coherenceSync component that replicates the transform and position. The component also changes the material based on if it is locally simulated or synced over the network.

    Coherence Entity Nav Agent has a Nav Mesh Agent component controlled via the Navigation Agent script which every few seconds sets a new destination on the grid. It's not required to sync anything other than the Transform; position, rotation parameter as the Nav Mesh Agent settings only need to simulate locally.

    Build and Try

    You can build this Scene via the Build Settings. Run the local Replication Server through the Window -> coherence -> Settings window and see how it works. You can try running multiple clients rather than just two and see replicating for each.

    LiveQuery

    LiveQuery

    The way you get information about the world is through LiveQueries. We set criteria for what part of the world we are interested in at each given moment. That way, the replicator won’t send information about everything that is going on in the game world everywhere, at all times.

    Instead, we will just get information about what’s within a certain area, kind of like moving a torch around to look in a dark cave.

    More complex areas of interest types are coming in future versions of coherence.

    Adding a LiveQuery to the scene

    A LiveQuery is a cube that defines the area of interest in a particular part of the world. It is defined by its position and its radius (half the side of the cube). There can be multiple LiveQueries in a single scene.

    Moving a LiveQuery

    A classic approach is to put a LiveQuery on the camera and set the radius to correspond to the far clipping plane or visibility distance.

    Moving the GameObject containing the LiveQuery will also notify the replication server that the query for that particular game client has moved.

    Entity references

    Entity references let you set up references between entities and have those be synchronized, just like other value types (like integers, vectors, etc.)

    To use Entity references, simply select any fields of type GameObject, Transform, or CoherenceSync for syncing in the Bindings window:

    The synchronization works both when using reflection and in baked sync scripts.

    Entity references can also be used as arguments in Commands.

    Limitations

    It's important to know about the situations when an entity reference might become null, even though it seems like it should have a value:

    • A client might not have the referenced entity in its live query. A local reference can only be valid if there's an actual entity instance to reference.

    • The owner of the entity reference might sync the reference to the Replication Server before syncing the referenced entity. This will lead to the Replication Server storing a null reference. If possible, try setting the entity references during gameplay when the referenced entities have already existed for a while.

    In any case, it's important to use a defensive coding style when working with entity references. Make sure that your code can handle missing entities and nulls in a graceful way.

    Replicator and Simulator Configuration

    Choosing Regions

    Click one or more regions you would like to run your replication and simulation services in, and click 'Save Regions'.

    Size your Replicator

    Click a replicator size best suited for the needs of your game and click the 'Save Sizing' button.

    Enable and Size the Simulator

    To enable the simulator, ensure that the 'Enabled' check box is checked. Choose a simulator size based on the needs of your game.

    Sample UI

    The coherence Sample UI prefab that comes bundled with the coherence SDK contains some basic UI controls that allows you to easily connect to and disconnect from servers.

    The connect dialog lists all available servers for your game. If the list is empty, please make sure you have setup your game on the coherence portal and deployed a replication server. Also make sure you have selected the correct region from the Region dropdown menu.

    If you want to be connect to a Replication Server running on your local machine, make sure you have ticked Local Development Mode under Project Settings -> coherence.

    The connect dialog comes in two flavors, one is for Rooms and the other is for Worlds. The Connect Dialog Rooms is enabled by default. If your project is configured for Worlds, you'll need to select the coherence Sample UI in the Hierarchy window and activate the Connect Dialog Worlds.

    Connect Dialog Rooms allows you to create or join rooms on the selected region.

    Connect Dialog Worlds allows you to join worlds on the selected region, but you can only create new worlds from the coherence portal.

    Note: You can also build your own interface to connect players to the server, or programmatically connect without any UI.

    Key-value store

    The key-value store provides a simple persistence layer for the players.

    Coherence.Play.DB

    This class provides the methods to set, get and unset key-value pairs. This is executed within the context of the currently logged in player.

    public static class KvStore
    {
        // Sets a value
        // key: lowercase letters, numbers, underscore, dash
        // val: any string (null is not allowed)
        public static void Set(string key, string val)
        
        // Gets a value
        // key: lowercase letters, numbers, underscore, dash
        public static string Get(string key)
        
        // Unsets a value, removing it from the store
        // key: lowercase letters, numbers, underscore, dash
        public static void Unset(string key)
    }

    Example

    Limitations

    Size: there are no limits to the number of stored key/values as long as the total size is less than 256kb.

    Requests: Set/Get/Unset can be called unlimited amount of times but the execution may be throttled.

    API tokens and keys

    Portal Token

    The token you get when creating a project on the developer portal.

    You paste it in the Project Settings.

    Runtime Key

    Once you have pasted the portal token successfully, you need to fetch the runtime key as well.

    You can fetch the by clicking on the down-arrow button on the right side of the input field.

    Simulator load balancing

    coherence allows us to use multiple simulators to split up a large game world with many entities between them. This is called spatial load balancing. Please refer to the section about simulators for more information.

    Our cloud services only support uploading one simulator to the cloud during our alpha. This will be extended in the near future. Enterprise customers can still run multiple simulators in their own cloud environment.

    Prefab setup

    In this section, we will learn how to prepare a prefab for network replication.

    1. Create a prefab and move it to Resources

    Add an asset and create a prefab of it. Make sure the prefab is in a Resources folder in your Unity project.

    Here is an example:

    Animations

    coherence doesn't replicate Animator state, but its parameters. Latency can create scenarios where different clients reproduce different animations. Take this into account when working with Animator Controllers that require precise timings.

    Unity Animator's parameters are bindable out of the box, with the exception of triggers.

    Settings Window

    Build and Run Server

    The coherence Settings window is located in Project Settings -> coherence and lets you launch a local replication server, upload your server to the cloud via the access token and bakes your Schemas for more optimized data transfer of Networked GameObjects.

    Enable CoherenceSync support

    Uncheck Enable CoherenceSync support

    Field Settings

    Many of the primitive data types in coherence supports configuration to make it possible to optimize the data being sent over the network. These settings can be made individually for each field of a component and will then be used throughout your code base.

    Syntax

    The field settings uses the meta data syntax in the schema, which looks like this:

    The meta data always goes at the end of the line and can be set on both definitions and the fields within a definition, like this:

    In this example, an ECS component named Health would be created, but instead of using the default 24 bits when sending its value, it would just use 8. Any updates to it would also be deprioritized compared to other components, so it could potentially be sent a bit late if bandwidth is scarse.

    Overview

    What is a simulator?

    A simulation server or simulator is a version of the game client without the graphics ("headless client") optimized and configured to perform server-side simulation of the game world. When we say something is simulated on the server, we mean it is simulated on one or several simulators.

    Network SDK

    SDK Overview

    The coherence SDK is a set of prefabs & scripts to help you create multiplayer games super fast.

    It makes it easy for anyone to create a multiplayer game by having flexible, intuitive and powerful visual components.

    Here are the main building blocks of the SDK.

    Overview

    The schema has two uses in your project:

    1. As a basis for code generation, creating various structs and methods that can be used in your project to communicate with the replication server.

    2. As a description for the Replication Server, telling it how the data in your project looks like – to receive, store, and send this data to its clients.

    When using MonoBehaviours and CoherenceSync you often don't need to interact with the schema directly.

    If you're writing your game using ECS/DOTS you will have to create and modify it yourself. Here's an example of a small schema:

    Key-value store

    Motivation

    coherence provides an API and a database for storing key-value pairs from within game sessions.

    Description

    public void OnRequest(ushort client)
    {
        var coherenceSync = target.GetComponent<CoherenceSync>();
        // do some extra checks
        // transfer authority
        coherenceSync.TransferAuthority(client);
        
        // or reject authority request
        // coherenceSync.RejectAuthorityRequest(client);
    }
    var coherenceSync = target.GetComponent<CoherenceSync>();
    coherenceSync.RequestAuthority();
    // There Unity Events in CoherenceSync help us understand 
    // what happened with authority requests and act accordingly.
    
    // called when the CoherenceSync entity becomes the simulation authority
    public UnityEvent OnAuthorityGained;
    
    // called when the CoherenceSync entity loses simulation authority
    public UnityEvent OnAuthorityLost;
    
    // called when a request to assume authority over the CoherenceSync entity
    // is rejected
    public UnityEvent OnAuthorityTransferRejected;
    var healthComponent = GetComponent<Health>();
    ...
    var healthField = healthComponent.health;
    //public float health;
    public float health2;
    Simulators can also be independent from the game code. A simulator could be a standalone application written in any language, including C#, Go or C++ , for instance. We will post more information about how to achieve this here in the future. For now, if you would like to create a simulator outside of Unity, please contact our developer relations team.

    Why do we need a simulator?

    A simulator can have various uses, including:

    • Server-side simulation of game logic that cannot be tampered with

    • Offloading processing from game clients

    • Splitting up a large game world with many entities between them

    Here are some examples of things a simulator could be taking care of:

    • Running all the important game logic

    • Running NPC AI

    • Simulating the player character (by receiving only inputs from the clients through input queues)

    How many simulators can we have per project?

    We can have as many simulators as we like. They will connect to the replication server like any other game client.

    Our cloud services only support uploading one simulator to the cloud during our alpha. This will be extended in the near future. Enterprise customers can still run multiple simulators in their own cloud environment.

    Enabling the Simulator

    See Enabling the simulator to enable the simulator for your project.

    CoherenceSync (Component)

    CoherenceSync is a component that should be attached to every networked Game Object. It may be your player, an NPC or an inanimate object such as a ball, a projectile or a banana. Anything that needs to be synchronized over the network. You can select which of the attached components you would like to sync across the network as well as individual public properties.

    Settings (Window)

    The coherence Settings window is located in Project Settings -> coherence and lets you launch a local replication server, upload your server to the cloud via the access token and bakes your schemas for more optimized data transfer of our Networked GameObjects.

    LiveQuery (Component)

    LiveQuery, as the name suggests, queries a location set by the developer so that coherence can simulate anything within its radius. In our Starter Project, the LiveQuery position is static with a radius large enough to cover the entire playable level. If the world was very large and potentially set over multiple simulation servers, the LiveQuery could be attached to the playable character or camera.

    MonoBridge (Component)

    The coherence MonoBridge passes information between the coherenceSync component and the networked ECS components.

    Sample UI

    The sample UI Prefab holds all of the UI and connection functionality to connect to the running project locally or via a server. You can completely rewrite this if you like, it's there to get you up and running quickly.

    The key/value store provides a simple way to store and retrieve data for the currently logged in player. For example, you could store player's score, email address, or any other data.

    It is important to mention that this feature requires a game account.

    Limitations

    The keys must be alphanumerical strings, underscore or dash. Currently, only strings are accepted as values. If you need to store numbers or complex types like arrays, you have to convert them to strings.

    The total amount of stored data (keys + values) cannot exceed 256 KB per player (TBD).

    There is no limit how often the data is stored or retrieved.

    Using key-value store

    Please refer to the Cloud API: Key-value store.

    Play.KvStore.Set("foo", "1");
    
    var foo = Play.KvStore.Get("foo");
    Debug.Log(string.Format("foo={0}", foo)); // foo=1
    
    Play.KvStore.Unset("foo");
    To learn more about the types and definitions available in a schema, see the specification.
    component Player
      name String64
      score Int
      
    component Enemy
      speed Float
      hp Int
      poisonous Bool

    Matchmaking

    The matchmaking provides a powerfull service to group players together in teams.

    Coherence.Play.Matchmaking

    The matchmaking module has only one method.

    // Invoked on success/failure
    public delegate void OnMatch(Result result, MatchResponse match);
    
    // The data for every player returned by the matchmaking request
    public struct PlayerPayload
    {
        public string user_id;
        public string team;
        public int score;
        public string payload;
    }
    
    // The response of the matchmaking request
    public class MatchResponse
    {
        public string match_id;
        public PlayerPayload[] players;
        public string error;
    }
    
    public static class Matchmaker
    {
        // Sends matchmaking request.
        // region:  matchmaking region, e.g. eu, us, ...
        // team:    team name
        // payload: custom string that will be send to all other players
        public static void Match(string region, string team, string payload, OnMatch callback)
        
        // Sends a matchmaking request
        // region:  matchmaking region, e.g. eu, us, ...
        // team:    team name
        // payload: custom string that will be send to all other players
        // tags:    custom tags to segment the player pool, e.g. "level1", "qa", etc
        // friends: group the player with his friends. If any of the friends doesn't show up the request will fail
        public static void Match(string region, string team, string payload, string[] tags, string[] friends, OnMatch callback)
    }
    

    Example

    Component updates do not only contain the actual data of the update, but also information about what entity should be affected, etc. This means that the total saving of data won't be quite as large as you'd think when going from 24 to 8 bits. Still, it's a great improvement!

    Priority

    All components support a piece of meta data that affects how highly the Replication Server will prioritize sending out updates for that particular component.

    This meta data is set on components, like this:

    The available priority levels are:

    • "very-low"

    • "low"

    • "mid" (default)

    • "high"

    • "very-high"

    Bit optimizations

    Some of the primitive types support optimizing the number of bits used to encode them when sending the over the network. It's worthwhile to think through if you can get away with less information than the default, to make room for more frequent updates.

    Float, Vector2, Vector3

    All of these types support the same two settings:

    • bits – how many bits the type should use to encode its floating point values

    • scale – the maximum and minimum value of each of its scalars (a scale of

    Integers

    Integers can be configured to only hold a certain range via:

    • range-min – the lowest possible value that the integer can hold

    • range-max – the largets possible value that the integer can hold

    Using these settings you can emulate other numeric types like char, short, unsigned int, etc.

    Quaternions

    Right now quaternions don't have any settings, but this will be remedied soon.

    Other types

    The other types doesn't have any settings that affect the number of bits they use. If they take up to much bandwith you'll have to try to send them less often, using priority, update frequency, or LODing.

    Matchmaker.Match("eu", "blue", "car:volvo,rifle:glock", (res, match) => {
        if (res == Result.Timeout) {
            // timed out, inform the player
            return
        }
        
        // match.players contain all the matched players and their data
        // including the this player
    }
    [key1 "value1", key2 "value2", etc...]
    component Health [prio "low"]
      value Float [bits "8"]
    component House [prio "low"]
    1.1 Create a simple Cube in the scene

    GameObject -> 3D Object -> Cube

    1.2 Convert the Cube into a prefab

    Create a Resources folder in your Project. Drag the Cube into the Resources folder to turn it into a prefab.

    It's important that your prefab is in a Resources folder so that Unity can load it at runtime. This is a Unity requirement, more info here.

    2. Add CoherenceSync to the prefab

    The CoherenceSync component will help you prepare an object for network synchronization during design time. It also exposes an API that allows us to manipulate the object during runtime.

    CoherenceSync will query all public variables and methods on any of the attached components, for example, Unity components such as Transform, Animator, etc. This will include any custom scripts such as PlayerInput and even scripts that came with Asset Store packages you may have downloaded.

    You can find out more about CoherenceSync here.

    3. Select variables to replicate

    Select which variables you would like to sync across the network. Initially, this will probably be the Transform settings; position, rotation, scale.

    Under Synchronization, click Select fields and methods.

    In the Bindings dialog, select position, rotation and scale.

    Close the Bindings dialog.

    4. Add an input script

    This simple input script will use WASD or the Arrow keys to move the prefab around the scene.

    Click on Assets -> Create -> C# Script.

    Name it Move.cs. Copy-paste the following content into the file.

    Wait for Unity to compile the file, then add it onto the prefab.

    5. Disable Input on replicated object

    We have added a Move script to the prefab. This means that if we just run the scene, we will be able to use the keyboard to move the object around.

    But what happens on another client where this object is not authoritative, but rather replicated? We will want the position to be replicated over the network, without the keyboard input interfering with it.

    Open the Events section in CoherenceSync. Add a new On Network Instantiation handler by clicking on the plus sign next to it.

    Pull the Cube prefab into the Runtime Only / None (Object) field.

    Now click the dropdown No Function and select Move -> bool enabled.

    Leave the Boolean field unchecked.

    6. Additional CoherenceSync settings

    From the CoherenceSync component you can configure settings for Lifetime (Session-based or Persistent, Authority (Not Transferable,Request or Stealing), Adoption settings for when local persistent entities are orphaned, Simulation type (Client Side or Server Side with Client Input), Interpolation Loop (CUpdate, Late Update, Fixed Update, Update and Fixed Update and Late Update and Fixed Update) and Manual Position Update.

    You can also control what happens when the prefab is instantiated or destroyed over the network in the Network Instantiation section. Where you can also have the networked object be instantiated as a different prefab altogether.

    You can find more information in the SDK Fundamentals. There are also some Events that are triggered at different times.

    • On Networked Instantiation (when the GameObject is instantiated)

    • On Networked Destruction (when the GameObject is destroyed)

    • On Authority Gained (when authority over the GameObject is transferred to the local client)

    • On Authority Lost (when authority over the GameObject is transferred to another client)

    • On After Authority Transfer Rejected (when GameObject's Authority transfer was requested and denied).

    Extras

    Helper scripts and samples can be found here.

    Triggers

    Triggers can be invoked over the network using commands. Here's an example where we inform networked clients that we have played a jump animation:

    Now, bind to PlayJumpAnimator.

    Speed and Pose parameters are available bindings on CoherenceSync
    using UnityEngine;
    using Coherence.Toolkit;
    using System.Collections.Generic;
    
    public class JumpController : MonoBehaviour
    {
        CoherenceSync coherenceSync;
        Animator animator;
    
        void Awake()
        {
            coherenceSync = GetComponent<CoherenceSync>();
            animator = GetComponent<Animator>();
        }
    
        void Update()
        {
            if (!coherenceSync.isSimulated)
            {
                return;
            }
    
            if (Input.GetKeyDown(KeyCode.Space))
            {
                MakePlayerJump();
            }
        }
    
        void MakePlayerJump()
        {
            coherenceSync.SendCommand<JumpController>(nameof(PlayJumpAnimation), MessageTarget.All, coherenceSync);
        }
    
        // bind to this method via the Bindings window
        public void PlayJumpAnimation(CoherenceSync jumpSync)
        {
            var animator = GetComponent<Animator>();
            animator.SetTrigger("Jump");
        }
    }
    to go pure ECS and use none of the visual tools.

    Bake Schemas

    When CoherenceSync variables/components are turned into ECS to send over the network, C# reflection is used to sync all the data at runtime. Whilst this is really useful for prototyping quickly and getting things working, it can be quite slow and poorly performing. A way to combat this is to bake the CoherenceSync component into a Schema.

    The Schema is a text file that defines which data types in your project are synced over the network. It is the source from which coherence SDK generates C# struct types (and helper functions) that are used by the rest of your game. The coherence Replication Server also reads the Schema file to know about those types and to communicate them with all of its clients efficiently.

    The Schema must be baked in the coherence Settings window, before the check box to bake this prefab can be clicked.

    When the CoherenceSync component is baked, it generates a new file in the Inspector of that Game Object called NameOfGameObject_Sync.

    Active Schemas

    Select the Schema files you want to use.

    • CoherenceSync (runtime reflection, slow)

    • CoherenceSync (baked, fast)

    Bake Output Folder

    Defines where to store the baked Schema files.

    Portal

    Upload your Schema files to your server.

    • Status - Current Status of your cloud server

    • Token - Cloud token

    Local Replication Server

    Run a local replication server.

    • Port - The port access

    • Frequency - Frequency of server.

    Start Tutorial
    Start Tutorial
    Start Tutorial
    Runtime Key
    Connect Dialog Rooms. There currently one room available on the local machine.

    Example – A global counter

    This document explains how to set up an ever increasing counter that all clients have access to. This could be used to make sure that everyone can generate unique identifiers, with no chance of ever getting a duplicate.

    By being persistent, the counter will also keep its value even if all clients log off, as long as the replication server is running.

    The Counter

    First, create a script called Counter.cs and add the following code to it:

    using UnityEngine;
    using Coherence.Toolkit;
    
    public class Counter : MonoBehaviour
    {
        public int counter = 0;
    
        public void NextNumber(CoherenceSync requester)
        {
            requester.SendCommand<NumberRequester>(
                nameof(NumberRequester.GotNumber), 
                MessageTarget.AuthorityOnly,
                counter);
            counter++;
        }
    }
    

    This script expects a command sent from a script called NumberRequester, which we will create below.

    Next, add this script to a prefab with CoherenceSync on it, and select the counterand the method NextNumber for syncing in the bindings window. To make the counter behave like we want, mark the prefab as "Persistent" and give it a unique persistence ID, e.g. "THE_COUNTER". Also change the adoption behaviour to "Auto Adopt":

    Finally, make sure that a single instance of this prefab is placed in the scene.

    NumberRequester

    Now, create a script called NumberRequester.cs. This will be an example MonoBehaviour that requests a unique number by sending the command GetNumber to the Counter prefab. As a single argument to this command, the NumberRequester will send an entity reference to itself. This makes it possible for the Counter to send back a response command (GotNumber) with the number that was generated. In this simple example we just log the number to the console.

    To make this script work, add it to a prefab that has the CoherenceSync script and mark the GotNumber for syncing in the bindings window.

    Client vs. simulator logic

    When scripting simulators, we need mechanisms to tell them apart.

    Am I a simulator?

    Ask Coherence.SimulatorUtility.IsSimulator.

    There are a few ways you can tell coherence if the instance should behave as a simulator:

    • Specifying a ConnectionType when connecting via Coherence.Network.Connect.

    • COHERENCE_SIMULATOR preprocessor define.

    • --coherence-simulation-server command-line argument.

    • Toggling on Simulator in the sample connection dialog.

    Connect and ConnectionType

    The Connect method on Coherence.Network accepts a ConnectionType parameter.

    COHERENCE_SIMULATOR

    Whenever the project compiles with the COHERENCE_SIMULATOR preprocessor define, coherence understands that the game will act as a simulator.

    Command-line argument

    Launching the game with --coherence-simulation-server will let coherence know that the loaded instance must act as a simulator.

    You can supply additional parameters to a simulator that define its area of responsibility, e.g. a sector/quadrant to simulate entities in and take authority over entities wandering into it.

    You can also build a special simulator for AI, physics, etc.

    Server-side simulation

    You can define who simulates the object in the CoherenceSync inspector.

    Automatic simulator adoption of CoherenceSync objects is work in progress and will be available in one of the future releases of coherence.

    Auto-reconnect

    The provided includes auto-reconnect behaviour out of the box for simulators. The root GameObject has an AutoReconnect component attached to it.

    If the simulator is invoked with the --coherence-play-region parameter, AutoReconnect will try to reconnect to the server located in that region.

    If you need a different solution, take a look at its implementation use plug your own.

    Start Tutorial

    The Network Playground project is a series of scenes with different features of coherence for you to pick through and learn.

    They will teach you the fundamentals that should set you on your way to creating a multiplayer game.

    Scenes

    Each Scene in this Network Playground Project shows you something new:

    • Scene 1. Synchronizing Transforms

    • Scene 2. Physics

    • Scene 3. Persistence

    • Scene 4. Synchronizing Animations and Custom Variables

    • Scene 5. AI Navigation

    • Scene 6. Network Commands

    • Scene 7. Network Teams

    Each scene comes with a few helpful core components.

    Core Scene setup

    This Prefab stores all the generic things that make up these simple Scenes.

    • Main Camera

    • Global Volume

    • Directional Light

    • Environment (Ground, Walls etc)

    coherence Setup

    This Prefab includes all of the things that make coherence work.

    • Interface

      • Canvas UI that handles Connection/Disconnection dialog and what address to connect.

    • Event System

    coherenceSync (on coherence Entity Prefab)

    We use this component on anything that we require to be networked, whether this is a playable character, NPC (non playing character), an object (ball, weapon, banana, car, plant etc) or any Game/Input Managers that require to sync data between Clients/Simulators/Servers.

    It scans the inspector for attached components and allows us to sync those component values (as long as they are public) and communicate them to other clients. It also allows us to set individual Prefabs persistent, authoritative and network connect/disconnect settings. There's much more information on the page.

    Replication Server

    The Replication Server replicates the state of the world to all connected Clients and Simulators.

    To understand what is happening in the game world, and to be able to contribute your simulated values, you need to connect to a Replication Server. The Replication Server acts as a central place where data is received from and distributed to interested clients.

    You can connect to a Replication Server in the cloud, but we recommend that you first start one locally on your computer. coherence is designed so you can easily develop everything locally first before deploying to the cloud.

    Replication Servers replicate data defined in schema files. The schema's inspector provides all the tools needed to start a Replication Server.

    1. Run the Replication Server by clicking the run button.

    2. A terminal/command line will pop up running your server locally

    3. The port the Replication Server will use. Default: 32001.

    4. The Replication Server frequency. Default: 60.

    You can also start the replication server from the coherence menu or by pressing ctrl+shift+alt+N.

    If you're unsure where schema files are located, you can easily search through the project using Unity's project search window, witht:Coherence.SchemaAsset

    To connect with multiple clients locally, publish a build for your platform (File > Build and Run, details in ). Run the Replication Server and launch the build any number of times. You can also enter Play Mode in the Unity Editor.

    For Mac Users: You can open new instances of an application from the Terminal:

    Connecting to a Replication Server

    When the replication server is running, you connect to it using the Connect command from one of your component systems.

    Connect to a Replication Server

    After trying to connect you might be interested in knowing whether the connection succeeded. The Connect call will run asynchronously and take around 100 ms to finish, or longer if you connect to a remote server. One way is to poll the once each tick until we know that it has succeeded. It is also possible to listen for a [network event]().

    Check if we are connected

    Check 'Run in Background' in the Unity settings under Project Settings -> Player so that the clients continue to run when not the active window.

    Make sure that your system is actually run, for example by adding the [AlwaysUpdateSystem] attribute to your system class. By default, Unity ECS will not run your system if it doesn't process any Entities.

    Archetypes and LOD-ing

    This document explains how to use Archetypes and LOD-ing in ECS/DOTS. If you're using coherence with MonoBehaviours, see this page instead.

    Basics

    Level of Detail (or LOD-ing, for short) is a technique to optimize the amount of data being sent from the replication server to each client. Often a client doesn't need to get as much information about an entity if it's far away. The way this is achieved when working with coherence is by using archetypes.

    Archetypes let you group components together and create distinct "levels of detail". Each such level must have a distance threshold, and a list of components that should be present at that distance. Optionally it can also contain per-field overrides that make the primitive data types in the components take up less space (at the cost of less precision.)

    To define an archetype, use the archetype keyword in your schema, then list the LODs in ascending order. Notice that LOD 0 does not need a distance, since it always starts at 0. Here's an example of a simple archetype:

    In this example, any Enemy entity that is 200 or more units away from the live query of a particular client will only get updates for the WorldPosition. Any client with a distance of 10 – 200 will get WorldPosition and WorldOrientation, and anything closer than that will get the full entity.

    Given one or more archetype definitions in your schema, you will have access to a few different data types and methods in your project (these will be generated when you run the Protocol Code Generator.)

    • ArchetypeComponent – this component has a field index that keeps track of which one of the archetypes in your schema that is being used. If you add the ArchetypeComponent yourself you have to use the static constants in the Coherence.Generated.Archetype to set the index. These all have the name "archetype name" + "Index", e.g. EnemyIndex in the example above.

    • An individual "tag" component (with no fields) called "archetype name" + "Archetype", e.g. EnemyArchetype in the example above. This component can be used to create optimized ForEach queries for a specific archetype.

    Field Overrides

    If a component isn't present at a certain LOD, no updates will be sent for that component. This is a great optimization, but sometimes a little too extreme. We might actually need the information, but be OK with a slightly less fine-grained version of it.

    To achieve this, you can use the same field settings that are available when defining components, but use them as overrides on specific LOD's instead.

    Here's an example of the syntax to use:

    Notice that the settings are exactly the same as when defining components. To override a field, you must know its name (value in this case.) Any field that is not overridden will use the settings of the LOD above, or the original component if at LOD 0.

    Priority

    Each component in an archetype can also override the default priority for that component. Just add the priority meta data after the component, like this:

    To read more about priority, see the page about .

    SDK Update Guide

    General Updates

    • After an sdk upgrade a bake process will be initiated automatically by the sdk to make sure the baked scripts are up to date.

    • If you run into any compilation or runtime errors in coherence code after the update these steps might help resolve the issue:

    1) Go to coherence -> Schema and Baking -> Bake schemas (Safe Mode)

    This will generate baked skeleton scripts which will compile but not work at runtime.

    2) Go to coherence -> Schema and Baking -> Bake schemas

    To fully generate the baked code (This can also be done via any of the other baking options).

    3) This process should handle old bindings which are different on the updated version. If the errors persist check the bindings window for the relevant prefab to make sure they are set up properly then perform steps 1 and 2 again.

    SDK Upgrade 0.4.x -> 0.5.0

    • Notable api changes you should be aware of:

    commands are now called like so:

    sync.SendCommand<ComponentType>("CommandMethodName", MessageTarget.All);

    For example:

    • Notice the MessageTarget parameter and generic type argument which might be missing in the version you were using before.

    Method parameters should be added after the MessageTarget parameter.

    • Notice the MessageTarget must be set for command methods in the Bindings window as well. If this is not set up in accordance with the way the method is called at runtime the command will not go through and a warning will be given about improper routing.

    Simulation Server

    coherence uses the concept of ownership to determine who is responsible for simulating each entity in the game world. By default, each client that connects to the server owns and simulates the entities they create. There are a lot of situations where this setup is not adequate. For example:

    • The number of entities in the game world could be too large to be simulated by the players on their own, especially if there are few players and the world is very large.

    • The game might have an advanced AI that requires a lot of coordination, which makes it hard to split up the work between clients.

    • It's often desirable to have an authoritative object that ensures a single source of truth for certain data. State replication and "eventual correctness" doesn't give us these guarantees.

    • Perhaps the game should run a persistent simulation, even while no one is playing.

    With coherence, all of these situations are can be solved using dedicated simulation servers. They behave very much like normal game clients, except they run on their own with no player involved. Usually they also have special code that only they run (and not the clients). It is up to the game developer to create and run these programs somewhere in the cloud, based on the demands of their particular game.

    Creating a simulation server

    If you have determined that you need one or more simulation servers for your game, there are multiple ways you can go about implementing these. You could create a separate Unity project and write the specific code for the simulation server there (while making sure you use the same schema as your original project).

    An easier way is to use your existing Unity project and modify it in a way so that it can be started either as a normal game client, or as a simulation server. This will ensure that you maximize code sharing between clients and servers -- they both do simulation of entities in the same game world after all.

    Please note that to build a simulation server, you have to build for the Linux platform.

    To determine whether to start a build as client or simulation server, you can use command line arguments:

    Reading command line arguments

    To pass the command line argument, start the application like this:

    When building stand-alone builds, Unity also has an option for . This is great for simulation servers since we're not interested in rendering any graphics on these anyway, and you can use it from code. By using headless mode we get a leaner executable that is easier to deploy in the cloud.

    To build server build change your build target to be Linux and tick Server build.

    Build and deploy

    Refer to the .

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Move : MonoBehaviour
    {
        public float speed = 1f;
    
        void Update()
        {
            float h = Input.GetAxisRaw("Horizontal");
            float v = Input.GetAxisRaw("Vertical");
        
            var spf = speed * Time.deltaTime;
    
            transform.position += transform.forward * (v * spf);
            transform.position += transform.right * (h * spf);
        }
    }
    using Coherence;
    
    if (SimulatorUtility.IsSimulator)
    {
        // I'm a simulator!
    }

    LastObservedLod – this component holds the current LOD for the entity. This can be used to detect when the entity changes LOD, if that's something you want to react to. Note that this component is not networked, since the exact LOD for an entity is unique for each client.

  • Static helper methods on the Archetype class to instantiate the archetype in a usable state. These are named "Instantiate" + "archetype name", e.g. InstantiateEnemy in the example above.

  • Field Settings
    archetype Enemy
      lod 0
        WorldPosition
        WorldOrientation
        Health
        AnimationState
        
      lod 1 [distance "10"]
        WorldPosition
        WorldOrientation
        
      lod 2 [distance "200"]
        WorldPosition
    archetype NPC
      lod 0
        WorldPosition
          value [bits "24"]
          
      lod 1 [distance "100"]
        WorldPosition
          value [bits "16"]
          
      lod 2 [distance "1000"]
        WorldPosition
          value [bits "8"]
    archetype NPC
      lod 0
        WorldPosition [prio "high"]

    Navigation Interface

    • To move between the Scenes without having to enter and exit playmode, useful when testing the standalone build.

  • Input Manager

    • Input Manager that uses Raycasting to send a message to the GameObject (with a collider) that it hit.

  • Event system to interact with any UI in the scene.
  • coherence Live Query

    • Game Object/Component with a query radius that coherence uses to ask the server "What is happening in the query radius?" so it does not query unnecessarily big areas of large worlds. You can find more information here.

  • coherence Mono Bridge

    • GameObject/Component to transform the Mono based coherenceSync component to archetypes so all data can be processed as ECS code.

  • CoherenceSync
    CoherenceSync inspector
    sample UI
    The custom build pipeline lets us define preprocessor defines like COHERENCE_SIMULATOR
    AutoReconnect in the sample UI
    Unity docs
    NetworkState
    headless mode
    Simulator: Build and deploy section

    Commands

    Overview

    Commands are network messages sent from one entity to another entity in the networked world. Commands bind to public methods accessible on the GameObject that CoherenceSync sits on.

    Design Phase

    In the design phase, you can expose public methods the same way you select fields for synchronization: by using the Select Bindings interface on your CoherenceSync object.

    Selected public methods will be exposed as network commands in the .

    The button on the right of the method lets you choose the routing mode. Commands with aSend to authority mode can be sent only to the authority of the target entity, while ones with the Send to all instances can be broadcasted to all clients that have a copy of this entity. The routing is enforced by the Replication Server as a security measure so the outdated or malicious clients don't break the game.

    The resulting schema section will look something like this:

    where routing metadata can have the following values:

    • "All" - (Send to all instances equivalent)

    • "AuthorityOnly" - (Send to authority equivalent)

    Sending a Command on a Networked Object

    To send a command, we call the SendCommand method on the target CoherenceSync object. It takes a number of arguments:

    • The type argument (within the <and>) must be the type of the recieving MonoBehaviour. This ensures that the correct method gets called if the receiving GameObject has components that implement methods which share the same name.

    • The first argument is the name of the method on the MonoBehaviour that we want to call. It is good practice to use the C# expression when referring to the method name, since it prevents accidentally misspelling it, or forgetting to update the string if the method changes name.

    • The second argument is an enum that specifies the

    Here's an example of how to send a command:

    Receiving a Command

    We don't have to do anything special to receive the command. The system will simply call the corresponding method on the target network entity.

    If the target is a locally simulated entity, SendCommand will recognize that and not send a network command, but instead simply call the method directly.

    Sending a Command to multiple entities

    Sometimes you want to inform a bunch of different entities about a change. For example, a explosion impact on a few players. To do so, we have to go through the instances we want to notify, and send commands to each of them.

    In this example, a will get sent to every network entity known to this client. To make it only affect entities within a certain criteria, you need to filter to which CoherenceSync you send the command to on your own.

    Supported types in Commands

    When a prefab is using reflection there are some restrictions for what types can be sent in a single command:

    • 4 integers

    • 4 floats

    • 4 bools

    • 4 entity references

    If you ever need to send commands containing any other type (like a vector) or a higher quantity (like two strings) you must mark the prefab to use . This will generate a custom command that can handle all the supported of the coherence SDK.

    If a single command is bigger than the supported packet size, it won't work even with baked code. For a good and performant game experience, always try to keep command sizes low.

    Specification

    Primitive Types

    These are the primitive types supported in a coherence schema:

    Int

    Uses a default range of -9999 to 9999.

    Float

    Uses a default scale of +/- 2400, which is encoded using 24 bits.

    Bool

    Encoded using a single bit.

    Vector2

    Encoded using two floats.

    Vector3

    Encoded using three floats.

    Quaternion

    String64

    The size of a string depends on its length. Try to keep the length of your strings as short as possible, or they won't fit inside a network package.

    Bytes4096

    An array of bytes with an upper limit of 4094 bytes (2 bytes reserverd for length).

    Currently we do not support automatic packet fragmentation and so packets bigger than the internal MTU (~1200 bytes) may be never sent.

    Entity

    The Entity type is used to keep references to other Entities. Technically the reference is stored as a local index that has to be resolved to an actual Entity before usage. Also, since a client might not know about the referenced Entity (due to it being outside of its live query) an Entity reference might be impossible to resolve in some circumstances. Your client code will have to take this into account and be programmed in a defensive way that handles missing Entities gracefully.

    Field Settings

    Several of the primitive types can be configured to take up less space when sent over the network, see .

    Components

    The most common definition in schemas is components, which correspond to ECS components in DOTS/ECS and to MonoBehaviours in regular Unity code.

    The definition takes a name of the component, and on the following lines an indented list of member variables, each one followed by their primitive type (see above.) The indentation has to be exactly 2 spaces. Here's how it might look:

    After code generation, this will give access to a component with the name Portal that has the members locked, connectedTo, and size.

    Optionally, each member/type pair can have additional meta data listed on the same line, using the following syntax:

    This is how it might look in an actual example:

    Built-in components

    There are some components that are built into the Protocol Code Generator and that you will always have access to.

    Archetypes

    Archetypes are used to optimize the sending of data from the server to each client, lowering the precision or even turning off whole components based on the distance from the live query to a particular Entity. Read more about how to define them in the schema on the page .

    Commands

    Commands are defined very similarly to components, but they use the command keyword instead.

    Here's a simple example Command:

    Routing defines to whom the command can be sent. Currently two values are supported:

    • AuthorityOnly - command will be received only by the owner of the target entity

    • All - command will be received by every client that has a copy of this entity

    When using reflection, there are limitations to what types are supported in commands. See the section for more information.

    Build and deploy

    Build a simulator to be uploaded to the cloud

    A simulator build is a built Unity Player for the Linux 64-bit platform that you can upload to coherence straight from Unity Editor.

    Make sure you have run through Build and run and .

    On Unity's menu bar, navigate to coherence -> Simulator -> Build Wizard.

    From within the Build Wizard you can build and upload simulators.

    The Info tab provides information and requirements to build simulators properly.

    The Build tab creates valid simulator builds from Build Configuration Assets.

    There's a known issue in the Platforms package provided by Unity where builds will fail when the project is not in the target build platform. To prevent this from happening, please switch your active platform to match the one used in your build configuration before building.

    Creating a Build Configuration Asset

    You can create them via Assets -> Create -> coherence -> Simulator Build Configuration.

    A newly created build configuration looks like this:

    There are several settings you might want to change.

    • Specify the scenes you want to get in the build via the Scene List component.

    • Specify a Company Name and a Version from the General Settings component (optional).

    • Additionally, you can add our OptimizeForSize component (find it using Add Component). Specify which optimizations you want to use to reduce the final build size from the Optimize For Size component (optional).

    Reducing simulator build size (experimental ⚠️)

    This feature is experimental, please make sure you backup your project beforehand.

    You can add an OptimizeForSize component to your build configuration via the Add Component in the build configuration inspector. It looks like this:

    Select the desired optimizations depending on your needs.

    Settings applied to built simulators will be reverted once the build process is completed, so these settings won't affect other builds you make.

    Upload your simulator

    Once you have created a valid simulator build, you can upload it to coherence.

    If you built your simulator using the Build tab, you should have a valid path to your simulator build set already. If you haven't or want to use a different path, use the Browse button.

    You'll see in the developer dashboard when your simulator is ready and running.

    Target frame rate on simulator builds is forced at 30.

    Game account

    Creating a player account is the first step towards using the coherence Cloud API. It is required in order to use the rest of the services.

    Initialization

    To initialize the Cloud API you need to provide a Runtime Key that can be obtained from the settings.

    Callbacks

    Guest Account

    The easiest way to get started is by using a guest account. The only thing that is needed is to call LoginAsGuest. This will create a random username / password combination and will authenticate the player with the coherence Cloud.

    Once logged in, the credentials are securely persisted so if the game is restarted the player will be able to log in automatically.

    If the game is uninstalled then the account credentials will be lost and a new guest account will be created next time the game is installed.

    User Account

    Another alternative is to login with a username and a password. You have to provide the user interface.

    Example

    This example initializes the Cloud API, checks for an existing session and, if no session was found or if it expired, logs in the player as guest.

    CoherenceSync

    CoherenceSync is a component that should be attached to every networked Game Object. It may be your player, an NPC or an inanimate object such as a ball, a projectile or a banana. Anything that needs to be synchronized over the network and turned into an Entity. You can select which of the attached components you would like to sync across the network as well as individual public properties.

    All Networked Entities need to be placed in the Resources folder

    Synced Variables and Commands

    Any scripts attached to the component with CoherenceSync that have public variables will be shown here and can be synced across the network. Enable the script + the variable to sync, it's that easy. Those variables with a lightning bolt next to them signify a public method that can be activated via commands.

    Persistence and Authority

    Ownership Transfer

    When you create a networked game object, you automatically become the owner of that game object. That means only you are allowed to update or destroy it. But sometimes it is necessary to pass ownership from one player to another. For example, you could snatch the football in a soccer game or throw a mind control spell in a strategy game. In this case, you will need to transfer ownership from one client to another.

    Entity Lifetime Type

    When a player disconnects, all the game objects created by that player are usually destroyed. If you want any game objects to stay in the game world after the owner disconnects, you need to set Entity lifetime type of that game object to Persistent.

    • Session Based - Will be removed when the client disconnects

    • Persistence - Entities with this option will persist as long as the server is running. Auto Generate Persistance UUID should be checked so that a unique identification string will be used to regenerate the object when you reconnect to the server. When the entity is spawned with this checked it will generate its own UUID.

    Entity Simulation Type

    • Client Side - Simulates everything on the local client and passes the information to the Replication Server to distribute that information to the other clients.

    • Other forms of simulation (Server; Server with Client Input) coming soon.

    Authority Transfer Style

    • Not Transferable - The default value is Not Transferable because most often objects are not meant to be transferred.

    • Stealing - Allows the game object to be transferred to another client.

    • Request - This option is intended for conditional transfers, which is not yet supported.

    Orphaned Entities

    By making the game object persistent, you ensure that it remains in the game world even after its owner disconnects. But once the game object has lost its owner, it will remain frozen in place because no client is allowed to update or delete it. This is called an orphaned game object.

    In order to make the orphaned game object interactive again, another client needs to take ownership of it. To do this, you need to set When orphaned to Auto Adopt.

    Transfer Request

    Once you have set the transfer style to stealing, any client can request ownership by calling the RequestAuthority() method on the CoherenceSync component of that game object:

    someGameObject.GetComponent<CoherenceSync>().RequestAuthority();

    A request will be sent to the game object's current owner. The current owner will then accept the request and complete the transfer.

    You are now the new owner of the game object. This means the isSimulated flag has been set to true, indicating that you are now in full control of the game object. The previous owner is no longer allowed to update or destroy it.

    with a custom implementation of Authority transfer can be found here.

    Connection Status

    When this object is synchronized over the network lets you set if you instantiate the specific prefab or an alternative one by giving its name path (Make sure it's in the Resources folder). Very useful if you are setting up a local player (with controls, camera etc) and a variant without those components.

    Event system for handling user connection and disconnection. Destroy Component Only is really useful for session based objects that you want to keep "semi persistent" which would be removed when all the clients disconnect.

    Bake/Optimize Script

    When CoherenceSync variables/components are turned into ECS to send over the network, C# reflection is used to sync all the data at runtime. Whilst this is really useful for prototyping quickly and getting things working, it can be quite slow and unperformant. A way to combat this is to bake the CoherenceSync component into a Schema.

    The schema is a text file that defines which data types in your project are synced over the network. It is the source from which coherence SDK generates C# struct types (and helper functions) that are used by the rest of your game. The coherence Replication Server also reads the Schema file so that it knows about those types and communicates them with all of its clients efficiently.

    The Schema must be baked in the coherence Settings window before the check box to bake this prefab can be clicked.

    When the CoherenceSync component is baked, it generates a new file in the Inspector of that Game Object called NameOfGameObject_Sync.

    OnNetworkedInstantiation and OnNetworkedDestruction

    OnNetworkedInstantiation is called when the network entity is instantiated by coherence. This is the best moment to make sure you prepare the GameObject the way you need. For example, disabling colliders or swapping materials.

    OnNetworkedDestruction is called when the network entity is going to be destroyed by coherence. The boolean parameter it takes reports if the destruction behavior is set to just destroy CoherenceSync rather than the Game Object.

    Commands

    Refer to the section.

    Server-side and input queues

    What are Input Queues?

    Input queues enable a simulator to take control of the simulation of another client's objects based on the client's inputs.

    When To Use Input Queues?

    using UnityEngine;
    using Coherence.Toolkit;
    
    public class NumberRequester : MonoBehaviour
    {
        CoherenceSync sync;
    
        private void Awake()
        {
            sync = GetComponent<CoherenceSync>();
        }
    
        void Update()
        {
            if(sync.isSimulated && Input.GetKeyDown(KeyCode.Return))
            {
                var counter = FindObjectOfType<Counter>();
                var counterSync = counter.GetComponent<CoherenceSync>();
                
                counterSync.SendCommand<Counter>(
                    nameof(Counter.NextNumber),
                    MessageTarget.AuthorityOnly,
                    sync);
            }
        }
    
        public void GotNumber(int number)
        {
            Debug.Log($"Got number: {number}");
        }
    }
    using Network = Coherence.Network;
    using ConnectionType = Replication.Client.Unity.Ecs.ConnectionType;
    
    public class ConnectAsSimulator : MonoBehaviour
    {
        void Start()
        {
            if (Network.Connect("127.0.0.1:32001", ConnectionType.Simulator))
            {
                // Connection successful
            }
            else 
            {
                // Connection failed
            }
        }
    }
    #if COHERENCE_SIMULATOR
    
    // simulator-specific code
    
    #endif
    open -n <path to .app>
    using Unity.Entities; 
    using Coherence.Replication.Client.Unity.Ecs;
    
    class MyComponentSystem : SystemBase 
    { 
        protected override void OnCreate() 
        { 
            World.GetExistingSystem().Connect("127.0.0.1:32001"); 
        } 
    }  
    protected override void OnUpdate() 
    { 
        // Method 1 
        if (World.GetExistingSystem().IsConnected) 
        { 
            // Yes, we are connected! This code will run every frame. 
        }
    
        // Method 2
        if (World.GetExistingSystem<NetworkSystem>().State == NetworkState.Connected)
        {
            // Yes, we are connected! This code will run every frame.
        }
        
        // Method 3
        Entities.ForEach((in ConnectedEvent connected) =>
        {
            // Yes, we are connected! This code will run only once.
        }).ScheduleParallel();
    }
    using System;
    
    class Boot : MonoBehaviour 
    { 
        void Start() 
        { 
            var args = Environment.GetCommandLineArgs(); 
            var isSimulationServer = false;
        
            foreach (var arg in args) {
                if(arg == "--coherence-simulation-server") {
                    isSimulationServer = true;
                }
            }
        
            /* do things based on 'isSimulationServer' here... */
        }
    }
    $ ./Game --coherence-simulation-server  
    public static class Play
    {
        // Initialises the Cloud API
        public static void Init(string RuntimeKey)
    }
    Network Playground Introduction
    field settings
    Archetypes and LOD-ing
    Supported types in commands
    component Portal
      locked Bool
      connectedTo Entity
      size Float
    [key1 "value1", key2 "value", etc...]
    component Portal
      locked Bool 
      connectedTo Entity [prio "high"]
      size Float [prio "low", bits "16"]
    command Damage [routing "AuthorityOnly"]
      amount Int
      explosive Bool
    public static class Auth
    {
        public enum Result
        {
            // Successful operation.
            Success,
            
            // Network error, e.g. connection failed.
            NetworkError,
            
            // Server error, e.g. exception on the server.
            ServerError,
            
            // User not found, e.g. when trying to login with non-existing user
            UserNotFound,
            
            // Invalid credentials, e.g. when trying to login with wrong password
            InvalidCredentials,
            
            // Session has expired, e.g. when trying to renew an existing session
            SessionExpired,
            
            // Feature is not enabled, e.g. K/V store
            FeatureDisabled,
        }
           
        // Invoked when completing the login process.
        public delegate void OnSession(Result result);
    }
    public static class Auth
    {
        // Authenticates the players as a guest.
        // callback - invoked upon completion.
        public static void LoginAsGuest(OnSession callback)
    }
    public static class Auth
    {
        // Authenticates the player with a username and a password.
        // userName   - any combination of letters, numbers, underscore and dash.
        // password   - any combination of ASCII characters
        // autosignup - whether to create an account automatically if it
        //              doesn't exist and the username is not taken
        // callback   - invoked upon completion
        public static void LoginAsUser(string userName, string password,
            bool autosignup, OnSession callback)
    }
    using Play = Coherence.Play;
    
    void OnLogin()
    {
        Debug.Log(string.Format("Logged in. PlayerId={0}", Play.Auth.UserId));
    }
    
    void Start()
    {
        // Initialise the Cloud API
        Play.Play.Init(apiToken);
        
        // Check for existing session
        Play.Auth.IsLoggedIn((res) => {
            if (res == Play.Result.Success)
            {
                // Session resumed
                OnLogin();
            }
            else if (res == Play.Result.SessionExpired || res == Play.Result.UserNotFound)
            {
                // No session found, or session expired. Proceed with normal login.
                Play.Auth.LoginAsGuest((res2) =>
                {
                    if (res2 == Play.Result.Success)
                    {
                        OnLogin();
                        return;
                    }
                    UnityEngine.Debug.LogError(string.Format("Could not login. Error={0}", res2));
                });
            }
            else
            {
                UnityEngine.Debug.LogError(string.Format("Could not login. Error={0}", res));
            }
        });
    }
    MessageTarget
    of the command. The possible values are:
    • MessageTarget.All – this will send the command to each client that has an instance of this entity.

    • MessageTarget.AuthorityOnly – this will send the command only to the client that has authority over the entity.

    Mind that the target must be compatible with the routing mode set in the bindings, i.e. Send to authority will allow only for the MessageTarget.AuthorityOnly while Send to all instances allows for both values.

  • The rest of the arguments (if any) vary depending on the command itself. We must supply as many parameters as are defined in the target method and the schema.

  • 1 string

  • 1 byte array

  • baking process
    nameof
    command
    baked code
    primitive types
  • In situations where you want a centralized simulation of all inputs. Many game genres use input queues and centralized simulation to guarantee the fairness of actions or the stability of physics simulations.

  • In situations where clients have low processing power. If the clients don't have sufficient processing power to simulate the world it makes sense to use input queue and just display the replicated results on the clients.

  • In situations where determinism is important. RTS and fighting games will use input queues and rollback to process input events in a shared (not centralized), and deterministic, way so that all clients simulate the same conditions and produce the same results.

  • coherence currently only supports using input queues in a centralized way where a single simulator is setup to process all inputs and replicate the results to all clients.

    Setup With CoherenceSync and CoherenceInput

    Setting up an object to simulate via input queues using CoherenceSync is done in three steps:

    1. Preparing the CoherenceSync component on the object prefab

    The Simulation Type of the CoherenceSync component is set to Simulation Server With Client Input

    CoherenceSync inspector

    Setting the simulation type to this mode instructs the client to automatically give authority over this object to the simulator in charge of simulating all inputs on all objects.

    2. Declaring Inputs for the simulated object

    Each simulated CoherenceSync component is able to define their own, unique, set of inputs for simulating that object. An input can be one of:

    • Button. A button input is tracked with just a binary on/off state.

    • Button Range. A button range input is tracked with a float value from 0 - 1.

    • Axis. An axis input is tracked as two floats from 0 - 1 in both the X and Y axis.

    To declare the inputs used by the CoherenceSync component, the CoherenceInput component is added to the object. The input is named and the fields are defined.

    In this example, the input block is named "Player Movement" and the inputs are WASD and "mouse" for the XY mouse position.

    3. Bake the CoherenceSync object

    In order for the inputs to be simulated on CoherenceSync objects, they must be optimized through baking.

    If the CoherenceInput fields or name is changed, then the CoherenceSync object must be re-baked to reflect the new fields / values.

    When a simulator is running it will find objects that are set up using CoherenceInput components and will automatically assume authority and perform simulations. In the case of a setup with multiple simulators, it is important that only one is designated as the processor of these objects. So, for all other simulators the InputServerSystem must be disabled.

    Using CoherenceInput

    Both the client and simulator need to access the inputs of the CoherenceInput of the replicated object. The client uses the Set* methods and the simulator uses the Get* methods to access the state of the inputs of the object. In all of these methods, the name parameter is the same as the Name field in the CoherenceInput component.

    Client-Side Set* Methods

    • public void SetButtonState(string name, bool value)

    • public void SetButtonRangeState(string name, float value)

    • public void SetAxisState(string name, Vector2 value)

    Simulator-Side Get* Methods

    • public bool GetButtonState(string name)

    • public float GetButtonRangeState(string name)

    • public Vector2 GetAxisState(string name)

    For example, the mouse click position can be passed from the client to the simulator via the "mouse" field in the setup example.

    The simulator can access the state of the input to perform simulations on the object which are then reflected back to the client as any replicated object is.

    Client-Side Prediction

    Generally, using server-side simulation with simulators makes the time from the client providing input to the time the object is updated with that input significantly longer than just client-side simulation because of the time required for the input to be sent to the simulator, processed, and then the updates to the object returned across the network. This can cause visual lag. Using input queues allows the client to perform prediction of the simulation to provide a smooth playing experience.

    If the client simulates the inputs on the object as well as applying them to the CoherenceInput component and then blends the authoritative results from the simulator with the locally simulated results, then smoother and more responsive simulation is achieved.

    Rollback is not currently available but is in the roadmap. Each client will be aware of the current global simulation frame and so the inputs can be applied by each client at the same frame in time and so client-side prediction can be even more accurate.

    Optimization

    What it does

    Replace Textures And Sounds With Dummies

    Project's textures and sound files are replaced with tiny and lightweight alternatives (dummies). Original assets are copied over to <project>/Library/coherence/AssetsBackup. They are restored once the build process has finished.

    Keep Original Assets Backup

    The Assets Backup (found at<project>/Library/coherence/AssetsBackup) is kept after the build process is completed, instead of deleted. This will take disk space depending on the size of the project, but it's a safety convenience.

    Compress Meshes

    Sets Mesh Compression on all your models to High.

    Disable Static Batching

    Static Batching tries to combine meshes at compile-time, potentially increasing build size. Depending on your project, static batching can affect build size drastically. Read more about static batching.

    Create an account
    Optimize For Size component, part of a Build Configuration Asset.
    Helper scripts
    commands

    Client messages

    Overview

    Client messages are a form of commands that are used for client-to-client communication rather than client-to-entity. To achieve this type of communication a special connection entity is automatically created by the replication server for each connected client. Those entities are subject to a different rule set than standard entities. Connection entities:

    • Can't be created or destroyed by the client - they are always replication server-driven

    • Are global - they are replicated across clients regardless of the in-simulation distance or radius

    Client messages shine whenever there's a need to communicate something to all the connected players. Usage examples:

    • Global chat

    • Game state changes: game started, game ended, map changed

    • Server announcements

    • Server-wide leaderboard

    Enabling client messages

    The globality of client messages doesn't fit all game types - for example, it rarely makes sense to keep every client informed about the presence of all players on the server in an MMORPG (think World Of Warcraft). Due to this reason, client messages are turned off by default. To enable client messages:

    1. Turn on the global query in the (the Global Query On toggle)

    Global query enables querying for entities containing a global component, including a connection entity.

    Disabling global query on one client doesn't affect other clients, i.e. connection entity of this client will still be visible to other clients that have the global query turned on.

    2. Create a class that inherits from the CoherenceClientConnection class

    Under the hood, client messages are nothing but sent between the connection entities. Each such entity is represented on the client side by an instance of a CoherenceClientConnection class. Implementing client messages is as simple as adding a new command to our custom connection class:

    Next, we have to create a binding:​

    3. Create a client connection prefab

    This step is described in detail in the . In short, a prefab with CoherenceSync and our PlayerConnection must be created and placed in the Resources directory:​

    4. Link the connection prefab to the MonoBridge

    For the system to know which object to create for every new client connection, we have to link our prefab to the Coherence MonoBridge. Simply drag the prefab to the Client Connection Prefab field in the MonoBridge inspector:​

    Connection management

    Once we have everything set up, whenever a new client joins an instance of the connection prefab will be created. The instantiated object resembles a client connection and will be kept alive for as long as that client remains connected to the replication server.

    To get notified about the creation and destruction of connections we can use the following events:

    The connection ID is simply an EntityID of the connection entity.

    To get local connection or connection of any client by the ID use the following MonoBridge methods:

    A null may be returned by both methods if client messages are not enabled or the connection with a given ID doesn't exist.

    The CoherenceClientConnection class exposes the following properties:

    Sending client messages

    Client messages are sent using the SendClientMessage method of the CoherencePlayerConnection class:

    The first message will be delivered only to the player that owns the created connection. The other message will be delivered to all instances of this connection, that is, every player (including the sender) that knows about this connection will receive this message.

    If the connection ID of the message recipient is known we can use the MonoBridge to send a client message:

    Interpolation

    Overview

    Depending on the settings in our project, data may not always arrive at a smooth 60 frames per second through the network. This is completely okay, but in order to make state changes (e.g. movement, rotation) appear smooth on the client, we use interpolation.

    Interpolation is a type of estimation, a method of constructing new data points within the range of a discrete set of known data points.

    The way interpolation works in coherence is that we wait for three data points and then start smoothing the subsequent values according to the interpolation parameters defined in the schema (or default parameters, if no overrides are present).

    Overriding interpolation settings

    To override interpolation settings, create a new schema asset via Assets/Create/coherence/Schema. Once created, mark it as an active schema in the settings window.

    In this new schema, add an interpolation definition:

    This interpolation definition MyInterpolation isn't used yet. We need to tell coherence which component is going to use it. We can associate it to WorldPosition and WorldOrientation:

    Although not necessary, we're also defining scale and bit depth in the example above.

    There are a few fields you can tune to get the most out of interpolation:

    • overshootPercentage

      • How far into dead reckoning we can venture when the time fraction exceeds 100%

    • overshootRetraction

    Interpolation can be overridden globally, per component and per LOD level. Here is a sample schema that defines a named interpolation style OverrideTranslation and uses it for all WorldPosition components.

    Here's another example that overrides interpolation for WorldPosition and WorldOrientation:

    Remember that everytime you change a schema, you need to Bake for the changes to make effect.

    We need one last piece to tie everything together. We need a way to let our bindings to use this interpolation override. To do so, we can create a custom binding provider that extends how the transform component is bound. Create a file named CustomTransformBindingProvider.cs in an Editor folder (e.g. Assets/Editor), with these contents:

    This will use OverrideTranslation interpolation component for WorldPosition, and OverrideRotation for WorldOrientation. You can use any name for these as long as it matches the names you defined in your schema. If you don't want to override one of these, just comment out the assignment you don't need.

    After you compile this script, a popup will appear letting you know that your CoherenceSync assets have been updated to point to these new components you defined.

    From here on, any additional change to interpolation you want to make, you can adjust the values in the schema and bake again.

    Level of detail

    Motivation

    coherence can support large game worlds with many objects. Since the amount of data that can be transmitted over the network is limited, it's very important to only send the most important things.

    You already know a very efficient tool for enabling this – the . It ensures that a client is only sent data when an object in its vicinity has been updated.

    Often though, there is a possibility for an even more nuanced and optimized approach. It is based on the fact that we might not need to send as much data for an entity that is far away, compared to a close one. A similar technique is often used in 3D-programming to show a simpler model when something is far away, and a more detailed when close-up.

    Helper Scripts

    Some extra scripts that are part of the Network Playground that may be useful

    command FemZombie_Character_SendDamage [routing "All"]
      damageValue Int
      staminaBlockCost Float
      staminaRecoveryDelay Float
      ignoreDefense Bool
      hitReaction Bool
      hitPosition Vector3
      sourceConnection Int
      isPlayer Bool
    var target = enemy.GetComponent<CoherenceSync>();
                        
    target.SendCommand<Character>(nameof(SendDamage), 
                    MessageTarget.All,
                    damageValue, staminaBlockCost,
                    staminaRecoveryDelay, ignoreDefense, 
                    hitReaction, hitPosition, 
                    ConnectionId, isPlayer);
    public void MulticastCommand()
    {
        var self = GetComponent<CoherenceSync>();
        var listeners = CoherenceSync.instances.Values;
        
        foreach (var listener in listeners)
        {
            if (!listener || listener == self)
            {
                continue;
            }
    
            listener.SendCommand<MyScript>(nameof(ReceiveCommand), MessageTarget.AuthorityOnly);
        }
    }
    
    // bind to this method via the Bindings window
    public void ReceiveCommand()
    {
        Debug.Log("Received!");
    }
    using Coherence.Generated.Internal;
    using Unity.Entities;
    
    public void DisableInputServerSystem()
    {
        var iss = World.DefaultGameObjectInjectionWorld.GetExistingSystem<InputServerSystem>();
        iss.Enabled = false;
    }
    using Coherence.Toolkit;
    using UnityEngine;
    
    public void SendMousePosition()
    {
        var coherenceInput = GetComponent<CoherenceInput>();
        var mousePos = Input.mousePosition;
        coherenceInput.SetAxisState("mouse", new Vector2(mousePos.x, mousePos.y));
    }
    using Coherence.Toolkit;
    using UnityEngine;
    
    public void ProcessMousePosition()
    {
        var coherenceInput = GetComponent<CoherenceInput>();
        var mousePos = coherenceInput.GetAxisState("mouse");
        
        //Move object
    }
    A simple spawn script that Instantiates the Networked Player on a Keypress
    Simple Input to get your Game Objects Moving 
    An Event System you put on the Prefab with coherenceSync
    that can handle Network Commands and transfer Authority
    An Event System you put on an empty game object in your 
    scene that handles Global Connection/Disconnection
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class SpawnCharacter: MonoBehaviour
    {
        public KeyCode KeyPress;
        public GameObject NetworkedCharacter;
        
        // Update is called once per frame
        void Update()
        {
            if(Input.GetKeyDown(KeyPress))
            {
                Instantiate(NetworkedCharacter);    
            }
        }
    }
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class SimpleMovement : MonoBehaviour
    {
        public float speed = 1f;
    
        void Update()
        {
            float h = Input.GetAxisRaw("Horizontal");
            float v = Input.GetAxisRaw("Vertical");
    
            transform.position += transform.forward * (v * speed * Time.deltaTime);
            transform.position += transform.right * (h * speed * Time.deltaTime);
        }
    }
    
    using Coherence;
    using UnityEngine;
    using UnityEngine.Events;
    using Coherence.Toolkit;
    
    public class CoherenceCommandHandler : MonoBehaviour
    {
        private CoherenceSync sync;
    
        public UnityEvent onCommandReceived;
    
        private GameObject fxInstance;
    
        private void Awake()
        {
            sync = GetComponent<CoherenceSync>();
        }
    
        public void Adopt()
        {
            if (!sync || sync.isSimulated)
            {
                return;
            }
    
            sync.RequestAuthority();
        }
    
        public void Orphan()
        {
            if (!sync || !sync.isSimulated)
            {
                return;
            }
    
            sync.AbandonAuthority();
        }
    
        public void ToggleAuthority()
        {
            if (!sync)
            {
                return;
            }
    
            if (sync.isSimulated)
            {
                Orphan();
            }
            else
            {
                Adopt();
            }
        }
    
        public void Command(CoherenceSync sender)
        {
            sync.SendCommand<SampleCommandHandler>("ReceiveCommand", MessageTarget.All);
        }
    
        public void ReceiveCommand()
        {
            onCommandReceived.Invoke();
        }
    
        public void InstantiateFX(GameObject fx)
        {
            if (fxInstance)
            {
                Destroy(fxInstance);
            }
    
            var t = fx.transform;
            fxInstance = Instantiate(fx, transform.position + t.position, transform.rotation);
        }
    }
    
    using UnityEngine;
    using UnityEngine.Events;
    using Coherence;
    
    public class CoherenceConnectionEvents : MonoBehaviour
    {
        public UnityEvent onConnect;
        public UnityEvent onDisconnect;
    
        private void OnEnable()
        {
            Coherence.Network.OnConnected += OnConnect;
            Coherence.Network.OnDisconnected += OnDisconnect;
        }
    
        private void OnDisable()
        {
            Coherence.Network.OnConnected -= OnConnect;
            Coherence.Network.OnDisconnected -= OnDisconnect;
        }
    
        private void OnConnect()
        {
            onConnect.Invoke();
        }
    
        private void OnDisconnect()
        {
            onDisconnect.Invoke();
        }
    }
    

    Server-wide events

    live query
    Coherence MonoBridge
    commands
    Prefab setup section
    MonoBridge inspector
    Binding a client message
    PlayerConnection prefab
    MonoBridge with linked connection prefab
    How fast to pull back to 100% if we overshoot the allowed dead reckoning maximum in seconds
  • manualLatency

    • Seconds to stay behind the sample data

  • autoLatencyFactor

    • targetInterpolation = autoLatencyFactor * packetDeltaTime . -1 disables auto latency

  • elasticity

    • Seconds to remain behind the current interpolation point, applied to smoothdamp function or slerp

  • maxDistance

    • maximum distance between data points before the component "teleports" to the next value without smoothing.

    • allowed values: positive real numbers

  • curveType

    • the type of interpolation used

    • allowed values: "CatmullRom", "Linear"

  • This idea works really well for networking too. For example, when another player is close to you it's important to know exactly what animation it is playing, what it's carrying around, etc. When the same player is far off in the horizon, it might suffice to only know it's position and orientation, since nothing else will be discernible anyways.

    To use this technique we must learn about something called archetypes.

    Archetypes

    An archetype is a component that can be added to any prefab with the CoherenceSync component. It contains a list of the various levels of detail (LODs) that this particular prefab can have.

    There must always exist a LOD 0, this is the default level and it always has all components enabled (it can have per-field overrides though, see below.)

    There can be any number of subsequent LODs (e.g. LOD 1, LOD 2, etc.) and each one must have a distance threshold higher than the previous one. The coherence SDK will try to use the LOD with the highest number, but that is still within the distance threshold.

    Example

    An object has three LODs, like this:

    • LOD 0 (threshold 0)

    • LOD 1 (threshold 10)

    • LOD 2 (threshold 20)

    If this object is 15 units away, it will use LOD 1.

    Confusingly, the highest numbered LOD is usually called the lowest one, since it has the least detail.

    One each LOD, there are two options for optimizing data being transferred:

    1. Components can be turned off, meaning you won't receive any updates from it.

    2. It's fields can be configured to use fewer bits, usually leading to less fine-grained information. The idea is that this won't be noticeable at the distance of the LOD.

    Scale, bits and range

    coherence allows us to define the scale of numeric fields and how many bits we want to allocate to them.

    Here are some terms we will be using:

    • Scale. The minimum/maximum value of the field before it overflows. A scale of 2400 means the number can run from -2400 to 2400.

    • Bits. The number of bits (octets) user for the field. When used for vectors, the number defined the number of bits used for each component (x, y and z). A vector3 set to 24 bits will consume 3 * 24 = 72 bits.

    • Range. For integer values, we define a minimum and maximum possible value (e.g. Health can lie between 0 and 100).

    More bits means more precision. Increasing the scale while leaving the bit count the same will lower the precision of the field.

    The maximum number of bits used for any field/component is currently 32.

    coherence allows us to define these values for specific components and fields. Furthermore, we can define levels of detail so that precision and therefore bandwidth consumption falls with the distance of the object to the point of observation.

    Levels of detail are calculated from the distance between the entity and the center of the LiveQuery.

    Defining levels of detail

    On each LOD you can configure the individual fields of any component to use less data. You can only decrease the fidelity, so a field can't use more data on a lower (more far away) LOD. The Archetype editor interface will help you to follow these rules.

    In order to define levels of detail, we have to add a CoherenceArchetype component to a prefab with CoherenceSync defined field bindings.

    CoherenceSync inspector

    Clicking on the Edit LOD button opens the Archetype Editor (and adds a CoherenceArchetype component if there wasn't one already).

    We can override the base component settings even without defining further levels of detail.

    Clicking on Add new Level Of Detail will add a new LOD. We can now define the distance at which the LOD starts. This is the minimum distance between the entity and the center of the LiveQuery at which the new level of detail becomes active (i.e. the replicator will start sending data as defined here at this distance).

    You can also disable components at later LOD levels if they are not needed. In the example above, you can see that the entire Animator component is disabled beyond the distance of 100 units. At 100 units (a.k.a. meters), we usually do not see animation details, so it does not make sense to replicate this data.

    The Data Cost Overview shows us that this takes the original 416 bits down to just 81 bits at LOD level 2.

    Field overrides per type

    The primitive types that coherence supports can be configured in different ways:

    Float, Vector2 & Vector3

    These three types can all be configured in the same way:

    1. By setting the scale, which affects the maximum and minimum value that the data type can take on. For example, a scale of 100 means that a float ranges from -100 to 100.

    2. By setting the precision, which defines the greatest deviation allowed for the data type. For example, a precision of 0.5 means that a float of value 10.0 can be transmitted as anything from 9.5 to 10.5 over the network.

    When using these scale setting for vectors, it affects each axis of the vector separately. Imagine shrinking its bounding box, rather than a sphere.

    Based on the scale and the desired precision, a bit count will be calculated. The default precision and scale (which happens to be 2400) gives a bit count of 24. This means that for a Vector3 a total of 72 bits will be used, 24 x 3.

    Integers

    Integers can be configured to any span (that fits within a 32-bit int) by setting its minimum and maximum value.

    For example, the member variable age in a game about ancient trolls might use a minimum of 100 and a maximum of 2000. Based on the size of the range (1900 in this case) a bit-count will be calculated for you.

    For integers it usually make sense to not decrease the range on lower LODs since it will overflow (and wrap-around) any member on an entity that switches to a lower LOD. Instead, use this setting on LOD 0 to save data for the whole Archetype.

    Quaternions

    Right now quaternions (used for rotations) do not support field overrides, but this will be fixed in the near future.

    Other types

    All other types (strings, booleans, entity references) have no settings that can be overridden, so your only option for optimizing those are to turn them off completely at lower LODs.

    LODs in the schema

    When we bake, information from the CoherenceArchetype component gets written into our schema. Below, you can see the setup presented earlier reflected in the resulting schema file.

    Caveats

    The most unintuitive thing about archetypes and LOD-ing is that it doesn't affect the sending of data. This means that a "fat" object with tons of fields will still tax the network and the replication server if it is constantly updated, even if it uses a very optimized Archetype.

    Also, it's important to realize that the exact LOD used on an entity varies for each other client, depending on the position of their query (or the closest one, if several are used.)

    LiveQuery

    Custom Bindings

    This is an advanced topic that aims to bring access to coherence's internals to the end user.

    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:

    CLI Utilities

    protocol-code-generator

    This tool has built in help that you can access like this:

    protocol-code-generator --help

    If you want information about a special command, instead do:

    protocol-code-generator --help generate

    public class PlayerConnection : CoherenceClientConnection
    {
        // My chat command
        public void OnChatMessage(string message)
        {
            Debug.Log($"Received chat message: {message}");
        }
    }
    public class GameManager : MonoBehaviour
    {
        public CoherenceMonoBridge MonoBridge;
    
        private void Start()
        {
            MonoBridge.OnConnectionCreated += OnConnectionCreated;
            MonoBridge.OnConnectionDestroyed += OnConnectionDestroyed;
        }
    
        private void OnConnectionCreated(CoherenceClientConnection clientConnection)
        {
            Debug.Log($"Client connected: {clientConnection.Id}");
        }
    
        private void OnConnectionDestroyed(CoherenceClientConnection clientConnection)
        {
            Debug.Log($"Client disconnected: {clientConnection.Id}");
        }
    }
    PlayerConnection myConnection 
        = MonoBridge.GetMyConnection<PlayerConnection>();
        
    PlayerConnection otherPlayerConnection 
        = MonoBridge.GetClientConnection<PlayerConnection>(otherPlayerId);
    PlayerConnection playerConnection = MonoBridge.GetMyConnection<PlayerConnection>(id);
    
    // ID of the connection (and connection entity)
    SerializeEntityID connectionId = playerConnection.Id;
    
    // True if this is connection belongs to the local client
    bool isMyConnection = playerConnection.IsMyConnection;
    
    // CoherenceSync of the connection object
    CoherenceSync sync = playerConnection.Sync;
    private void OnConnectionCreated(CoherenceClientConnection clientConnection)
    {
            clientConnection.SendClientMessage("OnChatMessage", MessageTarget.AuthorityOnly, "This is a private message");
    
            clientConnection.SendClientMessage("OnChatMessage", MessageTarget.All, "This is a global message");
    }
    private SerializeEntityID newestConnectionId;
    
    private void OnConnectionCreated(CoherenceClientConnection clientConnection)
    {
        if (!clientConnection.IsMyConnection)
        {
            newestConnectionId = clientConnection.Id;
        }
    }
    
    public void SendMessageToNewestConnection(string message)
    {
        MonoBridge.SendClientMessage("OnChatMessage", newestConnectionId, MessageTarget.AuthorityOnly, "Hello!");
    }
    interpolation MyInterpolation
      overshootPercentage 0
      overshootRetraction 0.0
      manualLatency 1
      autoLatencyFactor 1.0
      elasticity 0.05
      maxDistance 1
      curveType "Linear"
    component WorldPosition [priority "high"]
      value Vector3 [bits "24", scale "101000", interpolation "MyInterpolation"]
    
    component WorldOrientation [priority "high"]
      value Quaternion [bits "24", scale "101000", interpolation "MyInterpolation"]
    interpolation OverrideTranslation
      overshootPercentage 0
      overshootRetraction 0
      manualLatency 1
      autoLatencyFactor 1.1
      elasticity 0
      maxDistance 50000
      curveType "CatmullRom"
      
    component WorldPosition
      value Vector3 [bits "24", scale "101000", interpolation "OverrideTranslation"]
      
    archetype Destroyer
      lod 0
        WorldPosition
          value [bits "24", scale "101000", interpolation "OverrideTranslation"]
        Ship
      lod 1 [distance "25000"]
        WorldPosition
          value [bits "20", scale "101000", interpolation "OverrideTranslation"]
        Ship
      lod 2 [distance "40000"]
        WorldPosition
          value [bits "16", scale "101000", interpolation "OverrideTranslation"]
        Ship
      lod 3 [distance "70000"]
        WorldPosition
          value [bits "12", scale "101000", interpolation "OverrideTranslation"]
        Ship
    interpolation OverrideTranslation
      overshootPercentage 2
      overshootRetraction 0.25
      manualLatency 1
      autoLatencyFactor 1.2
      elasticity 0.045
      maxDistance 1024
      curveType "Linear"
    
    interpolation OverrideRotation
      overshootPercentage 0
      overshootRetraction 0.0
      manualLatency 1
      autoLatencyFactor 1.0
      elasticity 0.05
      maxDistance 1
      curveType "Linear"
      
    component WorldPosition [priority "high"]
      value Vector3 [bits "24", scale "101000", interpolation "OverrideTranslation"]
    
    component WorldOrientation [priority "high"]
      value Quaternion [bits "24", scale "101000", interpolation "OverrideTranslation"]
    
    
    using System.Collections.Generic;
    using UnityEngine;
    using Coherence.Toolkit;
    
    [CustomBindingProvider(typeof(Transform))]
    public class CustomTransformBindingProvider : TransformBindingProvider
    {
        public override void FetchDescriptors(Component component, List<CustomBinding.Descriptor> descriptors)
        {
            base.FetchDescriptors(component, descriptors);
            descriptors[0].interpolationComponentName = "OverrideTranslation";
            descriptors[1].interpolationComponentName = "OverrideRotation";
        }
    }
    
    archetype FemZombie
      lod 0
        WorldPosition 
          value 
        WorldOrientation 
          value 
        FemZombie_UnityEngine_Animator 
          InputHorizontal [bits "11", scale "1"]
          InputVertical [bits "11", scale "1"]
          InputMagnitude [bits "11", scale "1"]
          TurnOnSpotDirection [bits "11", scale "1"]
          ActionState [bits "15", range-min "0", range-max "10"]
      lod 1 [distance "50"]
        WorldPosition 
          value [bits "18", scale "2400"]
        WorldOrientation 
          value 
        FemZombie_UnityEngine_Animator 
          InputHorizontal [bits "11", scale "1"]
          InputVertical [bits "11", scale "1"]
          InputMagnitude [bits "11", scale "1"]
          TurnOnSpotDirection [bits "11", scale "1"]
          ActionState [bits "15", range-min "0", range-max "10"]
          IdleRandom [bits "15", range-min "-9999", range-max "-9999"]
          RandomAttack [bits "15", range-min "-9999", range-max "-9999"]
          AttackID [bits "15", range-min "-9999", range-max "-9999"]
          DefenseID [bits "15", range-min "-9999", range-max "-9999"]
          RecoilID [bits "15", range-min "-9999", range-max "-9999"]
          ReactionID [bits "15", range-min "-9999", range-max "-9999"]
          HitDirection [bits "15", range-min "-9999", range-max "-9999"]
      lod 2 [distance "100"]
        WorldPosition 
          value [bits "10", scale "2400"]
        WorldOrientation 
          value 
    Place CustomBindingProviders inside an Editor folder.

    We can add additional (custom) bindings:

    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.

    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:

    CustomBindingRuntimeSerializers should be placed in a non-Editor folder.

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

    Extending and inheriting CustomBindingProviders

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

    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:

    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).

    using UnityEngine;
    
    public class Health : MonoBehaviour
    {
        public int health;
    }
    using UnityEngine;
    using Coherence.Toolkit;
    
    [CustomBindingProvider(typeof(Health))]
    public class HealthBindingProvider : CustomBindingProvider
    {
        // check the CustomBindingProvider base class to
        // explore the possibilities!
    }
    
    using System.Collections.Generic;
    using UnityEngine;
    using Coherence.Toolkit;
    
    [CustomBindingProvider(typeof(Health))]
    public class CustomTransformBindingProvider : CustomBindingProvider
    {
        public override void FetchDescriptors(Component component, List<CustomBinding.Descriptor> descriptors)
        {
            base.FetchDescriptors(component, 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",
            });
        }
    }
    
    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(CoherenceMonoBridge monoBridge, CustomBinding customBinding, ICoherenceComponentData componentData)
        {
            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 valeu of health
                // in this example, we just do some custom logic: updating the isAlive bool with it
                health.isAlive = v > 0;
            }
        }
    
        public override void PerformInterpolation(CoherenceMonoBridge monoBridge, CustomBinding customBinding, AbsoluteSimulationFrame localFrame, float deltaTime)
        {
        }
    
        public override void ChangeInterpolationSetup(CustomBinding customBinding, string setupName)
        {
        }
    
        public override void ResetInterpolation(CustomBinding customBinding)
        {
        }
    }
    
    using System.Collections.Generic;
    using UnityEngine;
    using Coherence.Toolkit;
    
    [CustomBindingProvider(typeof(Health))]
    public class CustomTransformBindingProvider : CustomBindingProvider
    {
        // here
        public override CustomBindingRuntimeSerializer CustomBindingRuntimeSerializer => new HealthRuntimeSerializer();
    
        public override void FetchDescriptors(Component component, List<CustomBinding.Descriptor> descriptors)
        {
            base.FetchDescriptors(component, 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",
            });
        }
    }
    using System.Collections.Generic;
    using UnityEngine;
    using Coherence.Toolkit;
    
    [CustomBindingProvider(typeof(Transform))]
    public class CustomTransformBindingProvider : TransformBindingProvider
    {
        public override void FetchDescriptors(Component component, List<CustomBinding.Descriptor> descriptors)
        {
            base.FetchDescriptors(component, descriptors);
            // your changes
        }
        
        // ...
    }
    [CustomBindingProvider(typeof(Transform), 1)]

    Flags

    -d, --schema=STRING

    The schema file (.schema)

    -o, --output=STRING

    Output file

    --output-dir=STRING

    Output directory (can only be used together with --split)

    -c, --code=STRING

    -e, --ecs=STRING

    --sync=STRING

    When running the schema generator, it needs to know the location of the schema file and what kind of code it should generate.

    It will emit the generated code to stdout, so you have to pipe that to a text file in order to save it (for example using the > operator). Here's an example of how it can look:

    protocol-code-generator generate --code csharp --ecs unity --schema ./coherence.schema > ./generated/schema.cs

    The emitted file should be placed somewhere inside your Unity project.

    replication-server

    The replication server also has general and specific help.

    replication-server --help

    replication-server --help serve

    Flags

    --port=32001

    The port to listen to

    --stats-port=32000

    The port to listen for stats scrapers

    --dump

    Write network packets to capture files (.packets)

    --frequency=20

    The server update frequency

    --schema=STRING

    The schema file (.schema)

    To start the server, you need to give it the location of the schema, like this:

    replication-server serve --schema ../Assets/coherence/coherence.schema

    In the example above we're running the server from the coherence-bin directory right at the root of your project.

    You can also define other parameters like min-query-distance (the minimum distance the LiveQuery needs to move for the replicator to recognize a change), frequency, ip and port number.

    replication-server serve --min-query-distance 10 --port 32001 --frequency 320 --schema "C:\Users\tadej\Desktop\work\coherence\gamejam-stellar\Assets\Schemas\stellar.schema"

    simulation-server

    You can run coherence simulation server using

    ./sim_x86_64 --coherence-simulation-server

    persistence-client

    The persistence client has general and specific help.

    persistence-client serve --help

    persistence-client --help serve

    Flags

    --save-file-name="world.save" .

    The name of the persistent save file

    --save-folder="."

    The folder where the save file is written

    --save-frequency=30

    The frequency in which the save file is written, in seconds

    --host="127.0.0.1:32001"

    The host:port to connect to

    --dump

    Write network packets to capture files (.packets)

    General flags

    --log-level=LOG-LEVEL-STRING

    Log level

    --log-file=LOG-FILE-STRING

    Log output file

    --panic-on-error

    Enable/disable panic on error

    --entities=STRING

    Entity snapshot (.yaml)

    --parent-replicator=STRING

    Host address for parent replicator connection

    --use-world-partitioner

    If set, the binary_partitioner is used

    --disconnect-timeout=5000

    Disconnect timeout (in milliseconds)

    --debug-streams

    Use debug streams

    --max-entities=65536

    Maximum number of entities allowed

    --min-query-distance=0.1

    Minimum distance for query change

    --frequency=20

    The server update frequency

    --schema=STRING

    The schema file (.schema)

    --disconnect-timeout=5000

    Disconnect timeout (in milliseconds)

    --debug-streams

    Use debug streams

    --query-world-position="0,0,0"

    Position of the center of the entity query

    --query-radius=10000

    Radius of entity query