// serialization is needed by OnSerialize and by manual sending from authority void DeserializeFromReader(NetworkReader reader) { // put it into a data point immediately DataPoint temp = new DataPoint { // deserialize position, rotation, scale // (rotation is optionally compressed) localPosition = reader.ReadVector3(), localRotation = compressRotation ? Compression.DecompressQuaternion(reader.ReadUInt()) : reader.ReadQuaternion(), // use current target scale, so we can check boolean and reader later, to see if the data is actually sent. localScale = targetComponent.localScale, timeStamp = Time.time }; if (syncScale) { // Reader length is checked here, 12 is used as thats the current Vector3 (3 floats) amount. // In rare cases people may do mis-matched builds, log useful warning message, and then do not process missing scale data. if (reader.Length >= 12) { temp.localScale = reader.ReadVector3(); } else { Debug.LogWarning("Reader length does not contain enough data for a scale, please check that both server and client builds syncScale booleans match.", this); } } // movement speed: based on how far it moved since last time // has to be calculated before 'start' is overwritten temp.movementSpeed = EstimateMovementSpeed(goal, temp, targetComponent, syncInterval); // reassign start wisely // -> first ever data point? then make something up for previous one // so that we can start interpolation without waiting for next. if (start == null) { start = new DataPoint { timeStamp = Time.time - syncInterval, // local position/rotation for VR support localPosition = targetComponent.localPosition, localRotation = targetComponent.localRotation, localScale = targetComponent.localScale, movementSpeed = temp.movementSpeed }; } // -> second or nth data point? then update previous, but: // we start at where ever we are right now, so that it's // perfectly smooth and we don't jump anywhere // // example if we are at 'x': // // A--x->B // // and then receive a new point C: // // A--x--B // | // | // C // // then we don't want to just jump to B and start interpolation: // // x // | // | // C // // we stay at 'x' and interpolate from there to C: // // x..B // \ . // \. // C // else { float oldDistance = Vector3.Distance(start.localPosition, goal.localPosition); float newDistance = Vector3.Distance(goal.localPosition, temp.localPosition); start = goal; // teleport / lag / obstacle detection: only continue at current // position if we aren't too far away // // local position/rotation for VR support if (Vector3.Distance(targetComponent.localPosition, start.localPosition) < oldDistance + newDistance) { start.localPosition = targetComponent.localPosition; start.localRotation = targetComponent.localRotation; start.localScale = targetComponent.localScale; } } // set new destination in any case. new data is best data. goal = temp; }
// serialization is needed by OnSerialize and by manual sending from authority void DeserializeFromReader(NetworkReader reader) { // put it into a data point immediately DataPoint temp = new DataPoint { // deserialize position, rotation, scale // (rotation is compressed) localPosition = reader.ReadVector3(), localRotation = Compression.DecompressQuaternion(reader.ReadUInt32()), localScale = reader.ReadVector3(), timeStamp = Time.time }; // movement speed: based on how far it moved since last time // has to be calculated before 'start' is overwritten temp.movementSpeed = EstimateMovementSpeed(goal, temp, targetComponent.transform, syncInterval); // reassign start wisely // -> first ever data point? then make something up for previous one // so that we can start interpolation without waiting for next. if (start == null) { start = new DataPoint { timeStamp = Time.time - syncInterval, // local position/rotation for VR support localPosition = targetComponent.transform.localPosition, localRotation = targetComponent.transform.localRotation, localScale = targetComponent.transform.localScale, movementSpeed = temp.movementSpeed }; } // -> second or nth data point? then update previous, but: // we start at where ever we are right now, so that it's // perfectly smooth and we don't jump anywhere // // example if we are at 'x': // // A--x->B // // and then receive a new point C: // // A--x--B // | // | // C // // then we don't want to just jump to B and start interpolation: // // x // | // | // C // // we stay at 'x' and interpolate from there to C: // // x..B // \ . // \. // C // else { float oldDistance = Vector3.Distance(start.localPosition, goal.localPosition); float newDistance = Vector3.Distance(goal.localPosition, temp.localPosition); start = goal; // teleport / lag / obstacle detection: only continue at current // position if we aren't too far away // // local position/rotation for VR support if (Vector3.Distance(targetComponent.transform.localPosition, start.localPosition) < oldDistance + newDistance) { start.localPosition = targetComponent.transform.localPosition; start.localRotation = targetComponent.transform.localRotation; start.localScale = targetComponent.transform.localScale; } } // set new destination in any case. new data is best data. goal = temp; }
// serialization is needed by OnSerialize and by manual sending from authority static void SerializeIntoWriter(NetworkWriter writer, Vector3 position, Quaternion rotation, Compression compressRotation, Vector3 scale) { // serialize position writer.WriteVector3(position); // serialize rotation // writing quaternion = 16 byte // writing euler angles = 12 byte // -> quaternion->euler->quaternion always works. // -> gimbal lock only occurs when adding. Vector3 euler = rotation.eulerAngles; if (compressRotation == Compression.None) { // write 3 floats = 12 byte writer.WriteSingle(euler.x); writer.WriteSingle(euler.y); writer.WriteSingle(euler.z); } else if (compressRotation == Compression.Much) { // write 3 byte. scaling [0,360] to [0,255] writer.WriteByte(FloatBytePacker.ScaleFloatToByte(euler.x, 0, 360, byte.MinValue, byte.MaxValue)); writer.WriteByte(FloatBytePacker.ScaleFloatToByte(euler.y, 0, 360, byte.MinValue, byte.MaxValue)); writer.WriteByte(FloatBytePacker.ScaleFloatToByte(euler.z, 0, 360, byte.MinValue, byte.MaxValue)); } else if (compressRotation == Compression.Lots) { // write 2 byte, 5 bits for each float writer.WriteUInt16(FloatBytePacker.PackThreeFloatsIntoUShort(euler.x, euler.y, euler.z, 0, 360)); } // serialize scale writer.WriteVector3(scale); }