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

Was this helpful?

Export as PDF
  1. Manual
  2. Advanced topics
  3. Big worlds

World Origin Shifting

Creating massive multiplayer worlds

Was this helpful?

Unity has a well-known limitation of offering high precision positioning only within a few kilometers from the center of the world. A common technique to get around this limitation is to move the whole world underneath the player. This is called world origin shifting. Here's how you can use it with coherence.

Unity uses numbers to represent the world position of game objects in memory. While this format can represent numbers up to 3.4028235×10383.4028235 × 10^{38}3.4028235×1038, its precision decreases as the number gets larger. You can use this to see that already around the distance of 10610^6106 meters the precision of a 32-bit float is 1 meter, which means that the position can only be represented in steps of one meter or more. So if your Game Object moves away from the origin by 1000 kilometers it can be only positioned with the accuracy of 1000km and one meter, or at 1000km and two meters, but not in between. As a result, usable virtual worlds can be limited to a range of as little as 5km, depending on how precisely GameObjects need to be tracked.

World origin shifting in coherence

Having a single floating world origin as used in single player games is not sufficient for multiplayer games since each player can be located in different parts of the virtual world. For that reason, in coherence, all positions on the are stored in absolute coordinates, while each Client has its own floating origin position, to which all of their game object positions are relative.

Limitations

To represent the absolute position of Game Objects on the Replication Server, we use the 64-bit floating-point format. This format allows for sub-1mm precision out to distances of 5 billion kilometers. To keep the implementation simple, floating origin position and any Game Object's absolute position is limited to the 32-bit float range, but because of the Floating Origin, it will have precision of a 64-bit float when networked with other Clients.

Quick start guide

Here is a simple example how the floating origin could be used. We will create a script that is attached to the player Prefab and is active only on the Client with authority.

using Coherence.Toolkit;
using UnityEngine;

[RequireComponent(typeof(CoherenceSync))]
public class PlayerShifter : MonoBehaviour
{
    private CoherenceSync sync;

    private void Awake()
    {
        sync = GetComponent<CoherenceSync>();
    }

    private void Update()
    {
        // We don't want to shift floating origin based on other player's position.
        // The same can be achieved via components configuration in the CoherenceSync.
        if (!sync.HasStateAuthority)
        {
            return;
        }
            
        // If player moves farther than 100 meters from the current floating origin
        if (transform.position.magnitude > 100)
        {
            // Translate the floating origin so the player is back at (0, 0, 0)
            sync.CoherenceBridge.TranslateFloatingOrigin(transform.position);
        }
    }
}

Calling the CoherenceBridge.TranslateFloatingOrigin will shift all CoherenceSync objects by the translated vector, but you have to shift other non-networked objects by yourself. We will create another script which takes care of this.

using Coherence;
using Coherence.Toolkit;
using UnityEngine;

public class WorldShifter : MonoBehaviour
{
    public CoherenceBridge bridge;
    public Transform[] nonNetworkedObjectsToShift;

    private void Start()
    {
        bridge.OnFloatingOriginShifted += OnFloatingOriginShifted;
    }

    private void OnFloatingOriginShifted(FloatingOriginShiftArgs args)
    {
        foreach (var nonNetworkedObj in nonNetworkedObjectsToShift)
        {
            nonNetworkedObj.position -= args.Delta.ToUnityVector3();
        }
    }
}

When your floating origin changes, the CoherenceBridge.OnFloatingOriginShifted event is invoked. It contains arguments such as the last floating origin, the new one, and the delta between them. We use the delta to shift back all non-networked game objects ourselves. Since the floating origin is Vector3 of doubles we need to use ToUnityVector3 method to convert it to Vector3 of floats.

Advanced settings

To control what happens to your entities when you change your floating origin, you can use CoherenceSync's floatingOriginMode and floatingOriginParentedMode fields. Both are accessible from the inspector under Advanced Settings.

Available options for both fields are:

  • MoveWithFloatingOrigin - when you change your floating origin, the Entity is moved with it, so its relative position is the same and absolute position is shifted.

  • DontMoveWithFloatingOrigin - when you change your floating origin, the Entity is left behind, so its absolute position is the same and relative position is shifted.

Floating Origin Mode dictates what happens to the Entity when it is a Root Object in the scene hierarchy, and Floating Origin Parented Mode dictates what happens to it when its parented under another non-synced Game Object.

If the Entity is parented under another CoherenceSync Object (even using ), its local position will never be changed, since it will always be relative to the parent.

If you are using Cinemachine for your cameras, you'll need to call to notify them that the camera target has moved when you shift the floating origin.

CoherenceNode
OnTargetObjectWarped
32-bit floating-point
site
Replication Server