protected virtual void CustomClientRead(uint timeStamp, ref MyTimeStampValues serverPositionAndOrientation, VRage.Library.Collections.BitStream stream) { if (m_timestamp != null) { m_timestamp.ServerResponse(timeStamp, ref serverPositionAndOrientation); } }
public void Update(uint timeStamp) { if (m_timeStampData == null) { m_timeStampData = new SortedDictionary<uint, MyTimeStampValues>(); } if(m_entity == null|| m_entity.Physics == null) { m_timeStampData.Remove(timeStamp); return; } var matrix = m_entity.WorldMatrix; m_timeStampData[timeStamp] = new MyTimeStampValues() { EntityId = m_entity.EntityId, Transform = new MyTransformD(matrix), LinearVelocity = m_entity.Physics.LinearVelocity, AngularVelocity = m_entity.Physics.AngularVelocity, }; if (m_timeStampData.Count >= MAX_POSHISTORY) { m_timeStampData.Remove(m_timeStampData.First().Key); } m_currentTimestamp = timeStamp; }
public void Update(uint timeStamp) { if (m_entity == null || m_entity.Physics == null) { m_timeStampData.Remove(timeStamp); return; } var matrix = m_entity.WorldMatrix; m_timeStampData[timeStamp] = new MyTimeStampValues() { EntityId = m_entity.EntityId, Transform = new MyTransformD(matrix), LinearVelocity = m_entity.Physics.LinearVelocity, AngularVelocity = m_entity.Physics.AngularVelocity, }; if (m_timeStampData.Count >= MAX_POSHISTORY) { m_timeStampData.Remove(m_timeStampData.First().Key); } m_currentTimestamp = timeStamp; }
public void ServerResponse(uint timeStamp, ref MyTransformD serverPositionAndOrientation) { if (timeStamp < m_lastTSFromServer) { return; } if (m_timeStampData.ContainsKey(timeStamp) == false) { m_entity.PositionComp.SetWorldMatrix(serverPositionAndOrientation.TransformMatrix, null, true); return; } MyTimeStampValues cachedData = m_timeStampData[timeStamp]; var mat = m_entity.WorldMatrix; MyTransformD delta = UpdateValues(m_entity, ref serverPositionAndOrientation, ref cachedData); mat.Translation = serverPositionAndOrientation.Position; m_entity.PositionComp.SetWorldMatrix(mat, null, true); UpdateDeltaPosition(timeStamp, ref delta); m_lastTSFromServer = timeStamp; }
public void OverwriteServerPosition(uint timestamp, ref MyTimeStampValues data) { if (m_timeStampData.Count <= 0) return; for (uint i = timestamp; i <= m_currentTimestamp; ++i) { OverWriteData(i, ref data); } }
void UpdateData(uint i, ref Vector3 deltaLinear, ref Vector3 deltaAngular) { if (m_timeStampData.ContainsKey(i)) { MyTimeStampValues cachedData = m_timeStampData[i]; cachedData.LinearVelocity += deltaLinear; cachedData.AngularVelocity += deltaAngular; m_timeStampData[i] = cachedData; } }
void UpdateData(uint i, ref MyTransformD delta) { if (m_timeStampData.ContainsKey(i)) { MyTimeStampValues cachedData = m_timeStampData[i]; cachedData.Transform.Position += delta.Position; Quaternion.Multiply(ref delta.Rotation, ref cachedData.Transform.Rotation, out cachedData.Transform.Rotation); m_timeStampData[i] = cachedData; } }
void OverWriteData(uint i, ref MyTimeStampValues delta) { if (m_timeStampData.ContainsKey(i)) { MyTimeStampValues cachedData = m_timeStampData[i]; cachedData.LinearVelocity = delta.LinearVelocity; cachedData.Transform.Position = delta.Transform.Position; m_timeStampData[i] = cachedData; } }
public void UpdateDeltaPosition(uint timestamp, ref MyTimeStampValues data) { if (m_timeStampData.Count <= 0) { return; } for (uint i = timestamp; i <= m_currentTimestamp; ++i) { UpdateData(i, ref data); } }
public void OverwriteServerPosition(uint timestamp, ref MyTimeStampValues data) { if (m_timeStampData.Count <= 0) { return; } for (uint i = timestamp; i <= m_currentTimestamp; ++i) { OverWriteData(i, ref data); } }
void UpdateData(uint i, ref MyTimeStampValues delta) { if (m_timeStampData.ContainsKey(i)) { MyTimeStampValues cachedData = m_timeStampData[i]; cachedData.AngularVelocity += delta.AngularVelocity; cachedData.LinearVelocity += delta.LinearVelocity; cachedData.Transform.Position += delta.Transform.Position; cachedData.Transform.Position += delta.LinearVelocity * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS; Quaternion.Multiply(ref delta.Transform.Rotation, ref cachedData.Transform.Rotation, out cachedData.Transform.Rotation); m_timeStampData[i] = cachedData; } }
void ClientRead(VRage.Library.Collections.BitStream stream) { uint timeStamp = stream.ReadUInt32(); if (m_lastRecievedTimeStamp > timeStamp) { return; } m_lastRecievedTimeStamp = timeStamp; MyTimeStampValues serverPositionAndOrientation = new MyTimeStampValues(); serverPositionAndOrientation.Transform = new MyTransformD(); serverPositionAndOrientation.Transform.Position = stream.ReadVector3D(); serverPositionAndOrientation.Transform.Rotation = stream.ReadQuaternionNorm(); serverPositionAndOrientation.LinearVelocity = stream.ReadVector3(); serverPositionAndOrientation.AngularVelocity = stream.ReadVector3(); serverPositionAndOrientation.LinearVelocity /= MyEntityPhysicsStateGroup.EffectiveSimulationRatio; serverPositionAndOrientation.AngularVelocity /= MyEntityPhysicsStateGroup.EffectiveSimulationRatio; CustomClientRead(timeStamp, ref serverPositionAndOrientation, stream); }
public void ServerResponse(uint timeStamp, ref MyTimeStampValues serverPositionAndOrientation) { if (timeStamp < m_lastTSFromServer) return; if (m_timeStampData.ContainsKey(timeStamp) == false) { m_entity.PositionComp.SetWorldMatrix(serverPositionAndOrientation.Transform.TransformMatrix, null, true); return; } MyTimeStampValues cachedData = m_timeStampData[timeStamp]; MatrixD worldMatrix = m_entity.PositionComp.WorldMatrix; MyTimeStampValues delta = new MyTimeStampValues(); delta.Transform.Position = serverPositionAndOrientation.Transform.Position - cachedData.Transform.Position; double deltaL = delta.Transform.Position.Length(); MyCharacter character = (m_entity as MyCharacter); cachedData.Transform.Rotation = Quaternion.Inverse(cachedData.Transform.Rotation); Quaternion.Multiply(ref serverPositionAndOrientation.Transform.Rotation, ref cachedData.Transform.Rotation, out delta.Transform.Rotation); if (deltaL < (MyGridPhysics.ShipMaxLinearVelocity()/ (60f * Sync.RelativeSimulationRatio))) { delta.Transform.Position = delta.Transform.Position * 0.2; } delta.Transform.Rotation = Quaternion.Slerp(delta.Transform.Rotation, Quaternion.Identity, 0.2f); Vector3D position = worldMatrix.Translation; position += delta.Transform.Position; delta.LinearVelocity = serverPositionAndOrientation.LinearVelocity -cachedData.LinearVelocity; delta.AngularVelocity = serverPositionAndOrientation.AngularVelocity - cachedData.AngularVelocity; double deltaVelocity = delta.LinearVelocity.LengthSquared(); if (deltaVelocity > 0.1 * 0.1) { m_entity.Physics.LinearVelocity += delta.LinearVelocity; } deltaVelocity = delta.AngularVelocity.LengthSquared(); if (deltaVelocity > 0.01 * 0.01) { m_entity.Physics.AngularVelocity += delta.AngularVelocity; } Quaternion orientation = Quaternion.CreateFromForwardUp(worldMatrix.Forward, worldMatrix.Up); Quaternion normalized = cachedData.Transform.Rotation; normalized.Normalize(); cachedData.Transform.Rotation = normalized; normalized = serverPositionAndOrientation.Transform.Rotation; normalized.Normalize(); serverPositionAndOrientation.Transform.Rotation = normalized; double eps = 0.001; if (Math.Abs(Quaternion.Dot(serverPositionAndOrientation.Transform.Rotation, cachedData.Transform.Rotation)) < 1 - eps) { Quaternion.Multiply(ref delta.Transform.Rotation, ref orientation, out orientation); MatrixD matrix = MatrixD.CreateFromQuaternion(orientation); MatrixD currentMatrix = m_entity.PositionComp.WorldMatrix; Vector3D translation = currentMatrix.Translation; currentMatrix.Translation = Vector3D.Zero; if (currentMatrix.EqualsFast(ref matrix, 0.01) == false) { matrix.Translation = translation; m_entity.PositionComp.SetWorldMatrix(matrix, null, true); } } if (deltaL > (MyGridPhysics.ShipMaxLinearVelocity()/ (60f * Sync.RelativeSimulationRatio))) { m_entity.PositionComp.SetPosition(serverPositionAndOrientation.Transform.Position); } else if (deltaL > POSITION_TOLERANCE) { m_entity.PositionComp.SetPosition(position); } UpdateDeltaPosition(timeStamp, ref delta); m_lastTSFromServer = timeStamp; }
MyTransformD UpdateValues(MyEntity entity, ref MyTransformD serverPositionAndOrientation, ref MyTimeStampValues cachedData) { MyTransformD delta = new MyTransformD(); delta.Position = serverPositionAndOrientation.Position - cachedData.Transform.Position; cachedData.Transform.Rotation = Quaternion.Inverse(cachedData.Transform.Rotation); Quaternion.Multiply(ref serverPositionAndOrientation.Rotation, ref cachedData.Transform.Rotation, out delta.Rotation); delta.Rotation = Quaternion.Identity; MatrixD matrix = entity.WorldMatrix; matrix.Translation = Vector3D.Zero; MatrixD correctionMatrix = MatrixD.Multiply(matrix, delta.TransformMatrix); correctionMatrix.Translation += entity.WorldMatrix.Translation; entity.PositionComp.SetWorldMatrix(correctionMatrix, null, true); return(delta); }
public void ServerResponse(uint timeStamp, ref MyTimeStampValues serverPositionAndOrientation) { if (timeStamp < m_lastTSFromServer) { return; } if (m_timeStampData.ContainsKey(timeStamp) == false) { m_entity.PositionComp.SetWorldMatrix(serverPositionAndOrientation.Transform.TransformMatrix, null, true); return; } MyTimeStampValues cachedData = m_timeStampData[timeStamp]; MatrixD worldMatrix = m_entity.PositionComp.WorldMatrix; MyTimeStampValues delta = new MyTimeStampValues(); delta.Transform.Position = serverPositionAndOrientation.Transform.Position - cachedData.Transform.Position; double deltaL = delta.Transform.Position.Length(); MyCharacter character = (m_entity as MyCharacter); cachedData.Transform.Rotation = Quaternion.Inverse(cachedData.Transform.Rotation); Quaternion.Multiply(ref serverPositionAndOrientation.Transform.Rotation, ref cachedData.Transform.Rotation, out delta.Transform.Rotation); if (deltaL < (MyGridPhysics.ShipMaxLinearVelocity() / (60f * Sync.RelativeSimulationRatio))) { delta.Transform.Position = delta.Transform.Position * 0.2; } delta.Transform.Rotation = Quaternion.Slerp(delta.Transform.Rotation, Quaternion.Identity, 0.2f); Vector3D position = worldMatrix.Translation; position += delta.Transform.Position; delta.LinearVelocity = serverPositionAndOrientation.LinearVelocity - cachedData.LinearVelocity; delta.AngularVelocity = serverPositionAndOrientation.AngularVelocity - cachedData.AngularVelocity; double deltaVelocity = delta.LinearVelocity.LengthSquared(); if (deltaVelocity > 0.1 * 0.1) { m_entity.Physics.LinearVelocity += delta.LinearVelocity; } deltaVelocity = delta.AngularVelocity.LengthSquared(); if (deltaVelocity > 0.01 * 0.01) { m_entity.Physics.AngularVelocity += delta.AngularVelocity; } Quaternion orientation = Quaternion.CreateFromForwardUp(worldMatrix.Forward, worldMatrix.Up); Quaternion normalized = cachedData.Transform.Rotation; normalized.Normalize(); cachedData.Transform.Rotation = normalized; normalized = serverPositionAndOrientation.Transform.Rotation; normalized.Normalize(); serverPositionAndOrientation.Transform.Rotation = normalized; double eps = 0.001; if (Math.Abs(Quaternion.Dot(serverPositionAndOrientation.Transform.Rotation, cachedData.Transform.Rotation)) < 1 - eps) { Quaternion.Multiply(ref delta.Transform.Rotation, ref orientation, out orientation); MatrixD matrix = MatrixD.CreateFromQuaternion(orientation); MatrixD currentMatrix = m_entity.PositionComp.WorldMatrix; Vector3D translation = currentMatrix.Translation; currentMatrix.Translation = Vector3D.Zero; if (currentMatrix.EqualsFast(ref matrix, 0.01) == false) { matrix.Translation = translation; m_entity.PositionComp.SetWorldMatrix(matrix, null, true); } } if (deltaL > (MyGridPhysics.ShipMaxLinearVelocity() / (60f * Sync.RelativeSimulationRatio))) { m_entity.PositionComp.SetPosition(serverPositionAndOrientation.Transform.Position); } else if (deltaL > POSITION_TOLERANCE) { if (m_entity is MyCharacter) { (m_entity as MyCharacter).CacheMoveDelta(ref delta.Transform.Position); } else { m_entity.PositionComp.SetPosition(position); } } UpdateDeltaPosition(timeStamp, ref delta); m_lastTSFromServer = timeStamp; }
protected override void CustomClientRead(uint timeStamp, ref MyTimeStampValues serverPositionAndOrientation, VRage.Library.Collections.BitStream stream) { bool hasSupport = stream.ReadBool(); if (hasSupport) { long entityId = stream.ReadInt64(); Vector3D serverDelta = stream.ReadVector3D(); Vector3D serverSupportPos = stream.ReadVector3D(); if (!MyEntities.EntityExists(entityId)) { return; } MyEntity support = MyEntities.GetEntityById(entityId); MyTimeStampValues?clientTransform = m_timestamp.GetTransform(timeStamp); Vector3D clientDelta = Vector3.Zero; Vector3D clientVelocity = Vector3D.Zero; Quaternion rotationComp = Quaternion.Identity; if (clientTransform != null) { if (m_supportTimeStamp == null) { return; } MyTimeStampValues?supportTransform = m_supportTimeStamp.GetTransform(timeStamp); Vector3D supportPosition = support.PositionComp.WorldMatrix.Translation; if (supportTransform.HasValue) { supportPosition = supportTransform.Value.Transform.Position; if (supportTransform.Value.EntityId != entityId) { supportPosition = serverSupportPos; return; } } clientDelta = supportPosition - clientTransform.Value.Transform.Position; clientVelocity = clientTransform.Value.LinearVelocity; rotationComp = Quaternion.Inverse(clientTransform.Value.Transform.Rotation); } else { m_character.PositionComp.SetWorldMatrix(serverPositionAndOrientation.Transform.TransformMatrix, null, true); return; } MyTimeStampValues delta = new MyTimeStampValues(); Quaternion.Multiply(ref serverPositionAndOrientation.Transform.Rotation, ref rotationComp, out delta.Transform.Rotation); delta.Transform.Position = clientDelta - serverDelta; delta.LinearVelocity = serverPositionAndOrientation.LinearVelocity - clientVelocity; double deltaL = delta.Transform.Position.Length(); //if difference is more than if (deltaL < (MyGridPhysics.ShipMaxLinearVelocity() * Sync.RelativeSimulationRatio)) { delta.Transform.Position = delta.Transform.Position * 0.2; delta.Transform.Rotation = Quaternion.Slerp(delta.Transform.Rotation, Quaternion.Identity, 0.2f); } Quaternion normalized = delta.Transform.Rotation; normalized.Normalize(); delta.Transform.Rotation = normalized; normalized = serverPositionAndOrientation.Transform.Rotation; normalized.Normalize(); serverPositionAndOrientation.Transform.Rotation = normalized; Quaternion clientNormalized = clientTransform.Value.Transform.Rotation; clientNormalized.Normalize(); double eps = 0.001; if (Math.Abs(Quaternion.Dot(serverPositionAndOrientation.Transform.Rotation, clientNormalized)) < 1 - eps && m_character.IsDead == false) { Quaternion currentOrientation = Quaternion.CreateFromForwardUp(m_character.WorldMatrix.Forward, m_character.WorldMatrix.Up); Quaternion.Multiply(ref delta.Transform.Rotation, ref currentOrientation, out currentOrientation); MatrixD matrix = MatrixD.CreateFromQuaternion(currentOrientation); MatrixD currentMatrix = m_character.PositionComp.WorldMatrix; currentMatrix.Translation = Vector3D.Zero; if (currentMatrix.EqualsFast(ref matrix) == false) { if (m_character.Physics.CharacterProxy != null) { m_character.Physics.CharacterProxy.Forward = matrix.Forward; m_character.Physics.CharacterProxy.Up = matrix.Up; } } } if (deltaL > (MyGridPhysics.ShipMaxLinearVelocity() * Sync.RelativeSimulationRatio)) { m_character.PositionComp.SetPosition(serverPositionAndOrientation.Transform.Position); m_character.Physics.LinearVelocity = serverPositionAndOrientation.LinearVelocity; m_timestamp.OverwriteServerPosition(timeStamp, ref serverPositionAndOrientation); return; } else if (deltaL > 5.0f * MyTimestampHelper.POSITION_TOLERANCE) { m_character.CacheMoveDelta(ref delta.Transform.Position); } m_character.Physics.LinearVelocity += delta.LinearVelocity; m_timestamp.UpdateDeltaPosition(timeStamp, ref delta); } else { base.CustomClientRead(timeStamp, ref serverPositionAndOrientation, stream); } }
MyTransformD UpdateValues(MyEntity entity, ref MyTransformD serverPositionAndOrientation, ref MyTimeStampValues cachedData) { MyTransformD delta = new MyTransformD(); delta.Position = serverPositionAndOrientation.Position - cachedData.Transform.Position; cachedData.Transform.Rotation = Quaternion.Inverse(cachedData.Transform.Rotation); Quaternion.Multiply(ref serverPositionAndOrientation.Rotation, ref cachedData.Transform.Rotation, out delta.Rotation); delta.Rotation = Quaternion.Identity; MatrixD matrix = entity.WorldMatrix; matrix.Translation = Vector3D.Zero; MatrixD correctionMatrix = MatrixD.Multiply(matrix, delta.TransformMatrix); correctionMatrix.Translation += entity.WorldMatrix.Translation; entity.PositionComp.SetWorldMatrix(correctionMatrix, null, true); return delta; }
void ServerWrite(VRage.Library.Collections.BitStream stream, ulong clientId) { bool clientUpdate = m_clientUpdateFlag[clientId]; stream.WriteBool(clientUpdate); if (clientUpdate) { ClientData clientData = m_serverClientData[clientId]; m_clientUpdateFlag[clientId] = false; stream.WriteUInt32(clientData.TimeStamp); MyTransformD serverData = new MyTransformD(Entity.WorldMatrix); //rotation is calculated same way for both Quaternion serverRotation = serverData.Rotation; serverRotation.Normalize(); clientData.Transform.Rotation.Normalize(); MyTimeStampValues delta = new MyTimeStampValues(); serverRotation = Quaternion.Inverse(serverRotation); Quaternion.Multiply(ref clientData.Transform.Rotation, ref serverRotation, out delta.Transform.Rotation); bool applyRotation = false; double eps = 0.001; if (Math.Abs(Quaternion.Dot(clientData.Transform.Rotation, serverData.Rotation)) < 1 - eps) { applyRotation = true; } bool isValidPosition = true; bool correctServerPosition = false; CalculatePositionDifference(clientId, out isValidPosition, out correctServerPosition, out delta.Transform.Position); bool isValidClientPosition = isValidPosition; if ((correctServerPosition && isValidPosition) || applyRotation) { MatrixD matrix = Entity.WorldMatrix; MatrixD correctionMatrix = MatrixD.Multiply(matrix.GetOrientation(), delta.Transform.TransformMatrix); correctionMatrix.Translation += Entity.WorldMatrix.Translation; if (correctServerPosition) { isValidClientPosition = IsPositionValid(new MyTransformD(correctionMatrix)); } if (isValidClientPosition) { Entity.PositionComp.SetWorldMatrix(correctionMatrix, null, true); MyEntityPhysicsStateGroup support = MySupportHelper.FindPhysics(Entity); if (support != null && support.MoveHandler != null) { support.MoveHandler(ref matrix, ref correctionMatrix); } } else if (applyRotation) { correctionMatrix.Translation = Entity.WorldMatrix.Translation; Entity.PositionComp.SetWorldMatrix(correctionMatrix, null, true); } } stream.WriteBool(!isValidClientPosition); if (!isValidClientPosition) { serverData = new MyTransformD(Entity.WorldMatrix); stream.Write(serverData.Position); CustomServerWrite(m_serverClientData[clientId].TimeStamp, clientId, stream); } } stream.Write(Entity.Physics != null ? Entity.Physics.LinearVelocity * MyEntityPhysicsStateGroup.EffectiveSimulationRatio : Vector3.Zero); stream.Write(Entity.Physics != null ? Entity.Physics.AngularVelocity * MyEntityPhysicsStateGroup.EffectiveSimulationRatio : Vector3.Zero); }
public void UpdateDeltaPosition(uint timestamp, ref MyTimeStampValues data) { if (m_timeStampData.Count <= 0) return; for (uint i = timestamp; i <= m_currentTimestamp; ++i) { UpdateData(i, ref data); } }
void ClientRead(VRage.Library.Collections.BitStream stream) { uint timeStamp = stream.ReadUInt32(); if(m_lastRecievedTimeStamp > timeStamp) { return; } m_lastRecievedTimeStamp = timeStamp; MyTimeStampValues serverPositionAndOrientation = new MyTimeStampValues(); serverPositionAndOrientation.Transform = new MyTransformD(); serverPositionAndOrientation.Transform.Position = stream.ReadVector3D(); serverPositionAndOrientation.Transform.Rotation = stream.ReadQuaternionNorm(); serverPositionAndOrientation.LinearVelocity = stream.ReadVector3(); serverPositionAndOrientation.AngularVelocity = stream.ReadVector3(); serverPositionAndOrientation.LinearVelocity /= MyEntityPhysicsStateGroup.EffectiveSimulationRatio; serverPositionAndOrientation.AngularVelocity /= MyEntityPhysicsStateGroup.EffectiveSimulationRatio; CustomClientRead(timeStamp, ref serverPositionAndOrientation, stream); }
protected override void CustomClientRead(uint timeStamp, ref MyTimeStampValues serverPositionAndOrientation, VRage.Library.Collections.BitStream stream) { bool hasSupport = stream.ReadBool(); if (hasSupport) { long entityId = stream.ReadInt64(); Vector3D serverDelta = stream.ReadVector3D(); Vector3D serverSupportPos = stream.ReadVector3D(); if (!MyEntities.EntityExists(entityId)) return; MyEntity support = MyEntities.GetEntityById(entityId); MyTimeStampValues? clientTransform = m_timestamp.GetTransform(timeStamp); Vector3D clientDelta = Vector3.Zero; Vector3D clientVelocity = Vector3D.Zero; Quaternion rotationComp = Quaternion.Identity; if (clientTransform != null) { if(m_supportTimeStamp == null) { return; } MyTimeStampValues? supportTransform = m_supportTimeStamp.GetTransform(timeStamp); Vector3D supportPosition = support.PositionComp.WorldMatrix.Translation; if (supportTransform.HasValue) { supportPosition = supportTransform.Value.Transform.Position; if(supportTransform.Value.EntityId != entityId) { supportPosition = serverSupportPos; return; } } clientDelta = supportPosition - clientTransform.Value.Transform.Position; clientVelocity = clientTransform.Value.LinearVelocity; rotationComp = Quaternion.Inverse(clientTransform.Value.Transform.Rotation); } else { m_character.PositionComp.SetWorldMatrix(serverPositionAndOrientation.Transform.TransformMatrix, null, true); return; } MyTimeStampValues delta = new MyTimeStampValues(); Quaternion.Multiply(ref serverPositionAndOrientation.Transform.Rotation, ref rotationComp, out delta.Transform.Rotation); delta.Transform.Position = clientDelta - serverDelta; delta.LinearVelocity = serverPositionAndOrientation.LinearVelocity - clientVelocity; double deltaL = delta.Transform.Position.Length(); //if difference is more than if (deltaL < (MyGridPhysics.ShipMaxLinearVelocity() * Sync.RelativeSimulationRatio)) { delta.Transform.Position = delta.Transform.Position * 0.2; delta.Transform.Rotation = Quaternion.Slerp(delta.Transform.Rotation,Quaternion.Identity,0.2f); } Quaternion normalized = delta.Transform.Rotation; normalized.Normalize(); delta.Transform.Rotation = normalized; normalized = serverPositionAndOrientation.Transform.Rotation; normalized.Normalize(); serverPositionAndOrientation.Transform.Rotation = normalized; Quaternion clientNormalized = clientTransform.Value.Transform.Rotation; clientNormalized.Normalize(); double eps = 0.001; bool hasJetpack = m_character.JetpackComp != null; if (hasJetpack && m_character.JetpackComp.TurnedOn && m_character.IsDead == false) { if (Math.Abs(Quaternion.Dot(serverPositionAndOrientation.Transform.Rotation, clientNormalized)) < 1 - eps ) { Quaternion currentOrientation = Quaternion.CreateFromForwardUp(m_character.WorldMatrix.Forward, m_character.WorldMatrix.Up); Quaternion.Multiply(ref delta.Transform.Rotation, ref currentOrientation, out currentOrientation); MatrixD matrix = MatrixD.CreateFromQuaternion(currentOrientation); MatrixD currentMatrix = m_character.PositionComp.WorldMatrix; currentMatrix.Translation = Vector3D.Zero; if (currentMatrix.EqualsFast(ref matrix) == false) { if (m_character.Physics.CharacterProxy != null) { m_character.Physics.CharacterProxy.Forward = matrix.Forward; m_character.Physics.CharacterProxy.Up = matrix.Up; } } } } if (deltaL > (MyGridPhysics.ShipMaxLinearVelocity() * Sync.RelativeSimulationRatio)) { m_character.PositionComp.SetPosition(serverPositionAndOrientation.Transform.Position); m_character.Physics.LinearVelocity = serverPositionAndOrientation.LinearVelocity; m_timestamp.OverwriteServerPosition(timeStamp, ref serverPositionAndOrientation); return; } else if (deltaL > 5.0f*MyTimestampHelper.POSITION_TOLERANCE) { m_character.CacheMoveDelta(ref delta.Transform.Position); } m_character.Physics.LinearVelocity += delta.LinearVelocity; m_timestamp.UpdateDeltaPosition(timeStamp, ref delta); } else { base.CustomClientRead(timeStamp, ref serverPositionAndOrientation, stream); } }