Floating Origin and Multiplayer

Hello,
I tested this script for a Floating Origin http://wiki.unity3d.com/index.php?title=Floating_Origin to prevent problem with huge Distances.

But If a player reaches the threshold I got strange behavior of the Player SpaceShips.

The enviroment moves correctly but the ship of the other player is not moved with the enviroment, it is still at the relative position to the map origin.

The same for the other player: The ship of the other player reaches the threshold, and get set back to the map origin.

(sorry for the odd english)

Without knowing anything about your multiplayer code, there is not much we can tell you.

I guess the wiki solution you’ve posted is not really applicable in a multiplayer game, because it only considers the player and it’s vicinity. In the case where the other player is not within the threshold, there will be problems.

I’m afraid there is no easy solution to this, but i’m also very interested in space games and therefore i would like to discuss it with you. If you like, you can pm me via the forum and we can talk in our native language.

here is my complete Script. I have a Utility and a Constans Class, i think the names should be inform about the ussage (Like gravity constant and set main camera).
Vector3d is GitHub - sldsmkd/vector3d: Double precision Vector Libraries for Unity3D

using UnityEngine;
using System.Collections;

public class SpaceObjectRef : MonoBehaviour {

	public Vector3d realPosition;
	public Vector3d realVelocity;

	GameObject localRef;
	public GameObject localRefPrefab;

	public bool isActive;
	
	Vector3 localDeltaVelocity;
	Vector3 localVelocity;

	public Vector3 localOffset;

	Vector3 deltaPosition;

	GameObject space;
	GameObject localSpace;
	LocalSpace localSpaceData;
	GameObject skyBoxCam;
	GameObject playerCam;

	public double realPositionX;
	public double realPositionY;
	public double realPositionZ;

	public double realVelocityX;
	public double realVelocityY;
	public double realVelocityZ;

	public double distanceFormPlanet;
	public double distanceFormSurface;
	public double gravityForce;
	public Vector3 directionToPlanet;
	public double speed;

	public Planet planet;

	Vector3 position;
	public Quaternion rotation;
	public Vector3 angularVelocity;
	Vector3 velocity;

	Vector3 originPos;
	Vector3 originOffset;
	
	private float lastSynchronizationTime = 0f;
	private float syncDelay = 0f;
	private float syncTime = 0f;
	private Vector3 syncStartPosition = Vector3.zero;
	private Vector3 syncEndPosition = Vector3.zero;
	private Quaternion syncStartRotation = Quaternion.identity;
	private Quaternion syncEndRotation = Quaternion.identity;
	private bool gotSync = false;
	
	void Awake ()
	{
		GetValues();
		ApplyValues();

		localSpace = GameObject.Find("LocalSpace");

		skyBoxCam = GameObject.FindGameObjectWithTag("SkyBoxCam");


		space = GameObject.Find("Space");
		localSpaceData = localSpace.GetComponent<LocalSpace>();


		if(networkView.isMine)
		{
			isActive = true;
		}

		if(transform.parent == null)
		{
			transform.parent = space.transform;
		}
	}

	void Start () {

		if(isActive && localRefPrefab != null)
		{
			localRef = Instantiate(localRefPrefab, Vector3.zero, rotation) as GameObject;
			localRef.transform.parent = localSpace.transform;

			PlayerRef playerRef = localRef.GetComponent<PlayerRef> ();
			if(playerRef != null)
			{
				playerRef.owner = true;
				Utility.SetMainCam(playerRef.cam);
			}
			localSpaceData.localRefs.Add(this);
		}
	}

	void FixedUpdate()
	{
		if(networkView != null && !networkView.isMine)
		{
			SyncedMovement();
		}
		Gravitiy();
		LocalRef();
		UpdateValues();
	}

	void Update()
	{

	}

	void LateUpdate () {
		skyBoxCam.transform.position = transform.position;
		FloatingOrigin();
	}

	void FloatingOrigin()
	{
		if(isActive && localRef != null)
		{
			originPos = localRef.transform.position;
			if(originPos.magnitude > Constants.floatingOriginThreshold)
			{
				originOffset -= originPos;
				foreach(Transform child in localSpace.transform)
				{
					child.position -= originPos;
				}
			}
		}
	}

	void OnDestroy()
	{
		if(localRef != null)
		{
			Destroy(localRef);
		}
	}

	void OnTriggerEnter(Collider other)
	{
		if(isActive)
		{
			SpaceObjectRef spaceObjectRef = other.GetComponent<SpaceObjectRef>();
			localOffset = Convert.Vector3dToVector3((spaceObjectRef.realPosition - realPosition)*Constants.spaceScale);

			if(spaceObjectRef.localRefPrefab != null && spaceObjectRef.localRef == null)
			{
				spaceObjectRef.localRef = Instantiate(spaceObjectRef.localRefPrefab, localOffset, spaceObjectRef.rotation) as GameObject;
				spaceObjectRef.localRef.rigidbody.angularVelocity = spaceObjectRef.angularVelocity;
				spaceObjectRef.localRef.transform.parent = localSpace.transform;

				localSpaceData.localRefs.Add(spaceObjectRef);
			}
		}
	}

	void OnTriggerExit(Collider other) {
		if(isActive)
		{
			SpaceObjectRef spaceObjectRef = other.GetComponent<SpaceObjectRef>();
			if(spaceObjectRef.localRef != null)
			{
				Destroy(spaceObjectRef.localRef);
				localSpaceData.localRefs.Remove(spaceObjectRef);
            }
        }
	}
    
    void LocalRef()
	{
		if(localRef != null)
		{
			localDeltaVelocity = localRef.rigidbody.velocity - localVelocity;
			localVelocity = localRef.rigidbody.velocity;

			transform.rigidbody.velocity += localDeltaVelocity/Constants.spaceScale;

			if(isActive)
			{
				foreach(SpaceObjectRef otherRef in localSpaceData.localRefs)
				{
					if(!otherRef.isActive && otherRef.localRef != null)
					{
						otherRef.localOffset = Convert.Vector3dToVector3((otherRef.realPosition - realPosition)*Constants.spaceScale);
						otherRef.localRef.rigidbody.position = otherRef.localOffset + originOffset;
					}
				}
			}

		}
		transform.rigidbody.AddForce(Vector3.zero);
	}

	void GetValues()
	{
		if(realPositionX != 0 || realPositionY != 0 || realPositionZ != 0)
		{
			realPosition.x = realPositionX;
			realPosition.y = realPositionY;
			realPosition.z = realPositionZ;
		}
		else
		{
			realPosition = Convert.Vector3ToVector3d(transform.rigidbody.position);
		}

		//rotation = transform.rigidbody.rotation;

		realVelocity.x = realVelocityX;
		realVelocity.y = realVelocityY;
		realVelocity.z = realVelocityZ;
	}
    
    void ApplyValues()
	{
		position = Convert.Vector3dToVector3(realPosition);
		velocity = Convert.Vector3dToVector3(realVelocity);

		transform.rigidbody.position = position;
		//transform.rigidbody.rotation = rotation;
		transform.rigidbody.velocity = velocity;
	}

	void UpdateValues()
	{

		realPosition = Convert.Vector3ToVector3d(transform.rigidbody.position);
		realVelocity = Convert.Vector3ToVector3d(transform.rigidbody.velocity);

		if(localRef != null)
		{
			rotation = localRef.rigidbody.rotation;
			angularVelocity = localRef.rigidbody.angularVelocity;
		}

		position = transform.rigidbody.position;
		velocity = transform.rigidbody.velocity;

		realPositionX = realPosition.x;
		realPositionY = realPosition.y;
		realPositionZ = realPosition.z;

		realVelocityX = realVelocity.x;
		realVelocityY = realVelocity.y;
        realVelocityZ = realVelocity.z;

		speed = rigidbody.velocity.magnitude * Constants.spaceScale;
	}

	void Gravitiy()
	{
		if(planet != null)
		{
			distanceFormPlanet = Vector3d.Distance(realPosition, planet.realPosition) * Constants.spaceScale;
			distanceFormSurface = distanceFormPlanet -  planet.radius;


			gravityForce = Constants.gravityConstantD * ( planet.mass / ( distanceFormPlanet * distanceFormPlanet ) );

			Vector3d dir = planet.realPosition - realPosition;
			dir.Normalize();
			directionToPlanet = Convert.Vector3dToVector3(dir);

			rigidbody.AddForce( directionToPlanet * (float)(gravityForce/Constants.spaceScale), ForceMode.Acceleration);
		}
	}

	private void SyncedMovement()
	{
		if(gotSync == true && localRef != null)
		{
			syncTime += Time.deltaTime;
			rigidbody.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
			localRef.rigidbody.rotation = Quaternion.Slerp(syncStartRotation, syncEndRotation, syncTime / syncDelay);
		}
	}
	
	void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
	{
		Vector3 syncPosition = Vector3.zero;
		Quaternion syncRotation = Quaternion.identity;
		Vector3 syncVelocity = Vector3.zero;
		
		if (stream.isWriting)
		{
			syncPosition = rigidbody.position;
			stream.Serialize(ref syncPosition);

			if(localRef != null)
			{
				syncRotation = localRef.rigidbody.rotation;
				stream.Serialize(ref syncRotation);
			}

			syncVelocity = rigidbody.velocity;
			stream.Serialize(ref syncVelocity);
		}
		else
		{
			stream.Serialize(ref syncPosition);
			stream.Serialize(ref syncRotation);
			stream.Serialize(ref syncVelocity);

			rigidbody.velocity = syncVelocity;

			syncTime = 0f;
			syncDelay = Time.time - lastSynchronizationTime;
			lastSynchronizationTime = Time.time;
			
			syncEndPosition = syncPosition + syncVelocity * syncDelay;
			syncStartPosition = rigidbody.position;

			if(localRef != null)
			{
				syncEndRotation = syncRotation;
				syncStartRotation = localRef.rigidbody.rotation;
			}
			gotSync = true;
		}
	}

}