LogoLogo
⚠️ Outdated documentationGo to LatestHomeAPI
SDK 1.0
SDK 1.0
  • Welcome
  • Overview
    • What is coherence?
    • How does coherence work?
    • Rooms and Worlds
    • Features and Roadmap
    • Release Notes
    • Known Issues and Troubleshooting
  • Learning coherence
    • Beginner's Guide to Networking Games
    • First Steps tutorial
      • 1. Basic syncing
        • 1.2. Animation parameters
        • 1.3. Sending commands
      • 2. Physics / Authority transfer
      • 3. Areas of interest
      • 4. Parenting entities
      • 5. Complex hierarchies
      • 6. Persistence
    • Campfire project
      • Game mechanics
      • Leveraging object pooling
      • Remote interactions: Chairs
      • Remote interactions: Trees
      • A unique object with complex state
      • Custom instantiation and destruction
      • Running a server-side NPC
      • Playing audio and particles
      • A simple text chat
    • How to network...
      • Racing
      • Turn-based
      • First-Person Shooter
      • MMO
      • Fighting
  • Get started
    • Installation
    • Scene Setup
      • Samples
    • Prefab Setup: CoherenceSync
    • Local Development
      • Tips and Recommendations
    • coherence Cloud
      • Create a Free Account
      • Deploy a Replication Server
      • Share Builds
  • coherence SDK for Unity
    • Components
      • CoherenceSync
      • CoherenceBridge
      • CoherenceLiveQuery
      • CoherenceTagQuery
      • Order of execution
    • Asset Management
      • Using CoherenceSyncConfig to instantiate GameObjects locally
      • CoherenceSyncConfigRegistry Save Modes
    • Networking State Changes
      • Messaging with Commands
      • Hierarchies & Child Objects
        • Child GameObjects
        • Child CoherenceSyncs
        • Deep Child CoherenceSyncs
      • Animations
      • CoherenceSync References
      • [Sync] and [Command] Attributes
      • [OnValueSynced] Attribute
      • Supported Types
      • Creating your own syncable member
    • Baking (Code Generation)
    • Scene Management
    • Authority
      • Authority transfer
      • Server-authoritative setup
    • Lifetime
      • Persistence
      • Example – a global counter
    • Optimization
      • Simulation Frequency
      • Areas of Interest
      • Level of Detail (LOD)
    • Profiling
    • Interpolation
    • Rigid Bodies
    • Settings
    • Simulation Frame
    • Replication Server
    • Simulators
      • Scripting: Client vs Simulator
      • Local Development
      • World Simulators
      • Room Simulators
      • Simulator Slugs
      • Multi-Room Simulators
      • Build and Publish
      • Command-line arguments
      • Load Balancing
    • Client-Hosting
    • Client Connections
    • Rollback Networking Support
    • World Origin Shifting
    • CLI
    • Upgrading Unity SDK
      • Upgrading to coherence Unity SDK 1.0.0
      • Upgrading to coherence Unity SDK 0.9.0
  • coherence Cloud
    • Developer Portal
    • Dashboard
    • Worlds
    • Rooms
    • Lobbies
    • Game Services
      • Account
      • Key-Value Store
    • Using coherence Cloud in Unity
      • Worlds
      • Rooms
      • Lobbies
      • Game Services
        • Authentication Service (Player Accounts)
        • Key-value store
  • Schema explained
    • Overview
    • Specification
    • Field settings
    • Archetypes
  • coherence Scripting API
  • Additional resources
    • Community
    • Quick Samples
    • Continuous Integration
    • Unreal Engine Support
    • WebGL Support
    • Peer-to-Peer Support (P2P)
    • Pricing
    • SLA
    • Glossary
Powered by GitBook
On this page
  • Floating origin in coherence
  • Limitations
  • Quick start guide
  • Advanced settings

Was this helpful?

Export as PDF
  1. coherence SDK for Unity

World Origin Shifting

Creating massive multiplayer worlds

Last updated 1 year ago

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 floating origin. Here's how you can use floating origin 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 like bullets need to be tracked.

Floating origin 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