/// <summary> /// Deserialize a message from the network. /// </summary> /// <remarks> /// Only receives what it needs and decompresses floats if you chose to. /// </remarks> public static NetworkStateMirror Deserialize(this NetworkReader reader) { var msg = new NetworkStateMirror(); msg.state = new StateMirror(); var state = msg.state; // The first received byte tells us what we need to be syncing. byte syncInfoByte = reader.ReadByte(); bool syncPosition = shouldSyncPosition(syncInfoByte); bool syncRotation = shouldSyncRotation(syncInfoByte); bool syncScale = shouldSyncScale(syncInfoByte); bool syncVelocity = shouldSyncVelocity(syncInfoByte); bool syncAngularVelocity = shouldSyncAngularVelocity(syncInfoByte); state.atPositionalRest = shouldBeAtPositionalRest(syncInfoByte); state.atRotationalRest = shouldBeAtRotationalRest(syncInfoByte); NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); if (networkIdentity == null) { Debug.LogWarning("Could not find target for network StateMirror message."); return(new NetworkStateMirror()); } uint netID = networkIdentity.netId; int syncIndex = (int)reader.ReadUInt32(); state.ownerTimestamp = reader.ReadSingle(); // Find the GameObject GameObject ob = NetworkIdentity.spawned[netID].gameObject; if (!ob) { Debug.LogWarning("Could not find target for network StateMirror message."); return(new NetworkStateMirror()); } // It doesn't matter which SmoothSync is returned since they all have the same list. msg.smoothSync = ob.GetComponent <SmoothSyncMirror>(); if (!msg.smoothSync) { Debug.LogWarning("Could not find target for network StateMirror message."); return(new NetworkStateMirror()); } // Find the correct object to sync according to the syncIndex. for (int i = 0; i < msg.smoothSync.childObjectSmoothSyncs.Length; i++) { if (msg.smoothSync.childObjectSmoothSyncs[i].syncIndex == syncIndex) { msg.smoothSync = msg.smoothSync.childObjectSmoothSyncs[i]; } } var smoothSync = msg.smoothSync; state.receivedTimestamp = smoothSync.localTime; // If we want the server to relay non-owned object information out to other clients, set these variables so we know what we need to send. if (NetworkServer.active && !smoothSync.hasControl) { state.serverShouldRelayPosition = syncPosition; state.serverShouldRelayRotation = syncRotation; state.serverShouldRelayScale = syncScale; state.serverShouldRelayVelocity = syncVelocity; state.serverShouldRelayAngularVelocity = syncAngularVelocity; } if (smoothSync.receivedStatesCounter < smoothSync.sendRate) { smoothSync.receivedStatesCounter++; } // Read position. if (syncPosition) { if (smoothSync.isPositionCompressed) { if (smoothSync.isSyncingXPosition) { state.position.x = HalfHelper.Decompress(reader.ReadUInt16()); } if (smoothSync.isSyncingYPosition) { state.position.y = HalfHelper.Decompress(reader.ReadUInt16()); } if (smoothSync.isSyncingZPosition) { state.position.z = HalfHelper.Decompress(reader.ReadUInt16()); } } else { if (smoothSync.isSyncingXPosition) { state.position.x = reader.ReadSingle(); } if (smoothSync.isSyncingYPosition) { state.position.y = reader.ReadSingle(); } if (smoothSync.isSyncingZPosition) { state.position.z = reader.ReadSingle(); } } } else { if (smoothSync.stateCount > 0) { state.position = smoothSync.stateBuffer[0].position; } else { state.position = smoothSync.getPosition(); } } // Read rotation. if (syncRotation) { state.reusableRotationVector = Vector3.zero; if (smoothSync.isRotationCompressed) { if (smoothSync.isSyncingXRotation) { state.reusableRotationVector.x = HalfHelper.Decompress(reader.ReadUInt16()); state.reusableRotationVector.x *= Mathf.Rad2Deg; } if (smoothSync.isSyncingYRotation) { state.reusableRotationVector.y = HalfHelper.Decompress(reader.ReadUInt16()); state.reusableRotationVector.y *= Mathf.Rad2Deg; } if (smoothSync.isSyncingZRotation) { state.reusableRotationVector.z = HalfHelper.Decompress(reader.ReadUInt16()); state.reusableRotationVector.z *= Mathf.Rad2Deg; } state.rotation = Quaternion.Euler(state.reusableRotationVector); } else { if (smoothSync.isSyncingXRotation) { state.reusableRotationVector.x = reader.ReadSingle(); } if (smoothSync.isSyncingYRotation) { state.reusableRotationVector.y = reader.ReadSingle(); } if (smoothSync.isSyncingZRotation) { state.reusableRotationVector.z = reader.ReadSingle(); } state.rotation = Quaternion.Euler(state.reusableRotationVector); } } else { if (smoothSync.stateCount > 0) { state.rotation = smoothSync.stateBuffer[0].rotation; } else { state.rotation = smoothSync.getRotation(); } } // Read scale. if (syncScale) { if (smoothSync.isScaleCompressed) { if (smoothSync.isSyncingXScale) { state.scale.x = HalfHelper.Decompress(reader.ReadUInt16()); } if (smoothSync.isSyncingYScale) { state.scale.y = HalfHelper.Decompress(reader.ReadUInt16()); } if (smoothSync.isSyncingZScale) { state.scale.z = HalfHelper.Decompress(reader.ReadUInt16()); } } else { if (smoothSync.isSyncingXScale) { state.scale.x = reader.ReadSingle(); } if (smoothSync.isSyncingYScale) { state.scale.y = reader.ReadSingle(); } if (smoothSync.isSyncingZScale) { state.scale.z = reader.ReadSingle(); } } } else { if (smoothSync.stateCount > 0) { state.scale = smoothSync.stateBuffer[0].scale; } else { state.scale = smoothSync.getScale(); } } // Read velocity. if (syncVelocity) { if (smoothSync.isVelocityCompressed) { if (smoothSync.isSyncingXVelocity) { state.velocity.x = HalfHelper.Decompress(reader.ReadUInt16()); } if (smoothSync.isSyncingYVelocity) { state.velocity.y = HalfHelper.Decompress(reader.ReadUInt16()); } if (smoothSync.isSyncingZVelocity) { state.velocity.z = HalfHelper.Decompress(reader.ReadUInt16()); } } else { if (smoothSync.isSyncingXVelocity) { state.velocity.x = reader.ReadSingle(); } if (smoothSync.isSyncingYVelocity) { state.velocity.y = reader.ReadSingle(); } if (smoothSync.isSyncingZVelocity) { state.velocity.z = reader.ReadSingle(); } } smoothSync.latestReceivedVelocity = state.velocity; } else { // If we didn't receive an updated velocity, use the latest received velocity. state.velocity = smoothSync.latestReceivedVelocity; } // Read anguluar velocity. if (syncAngularVelocity) { if (smoothSync.isAngularVelocityCompressed) { state.reusableRotationVector = Vector3.zero; if (smoothSync.isSyncingXAngularVelocity) { state.reusableRotationVector.x = HalfHelper.Decompress(reader.ReadUInt16()); state.reusableRotationVector.x *= Mathf.Rad2Deg; } if (smoothSync.isSyncingYAngularVelocity) { state.reusableRotationVector.y = HalfHelper.Decompress(reader.ReadUInt16()); state.reusableRotationVector.y *= Mathf.Rad2Deg; } if (smoothSync.isSyncingZAngularVelocity) { state.reusableRotationVector.z = HalfHelper.Decompress(reader.ReadUInt16()); state.reusableRotationVector.z *= Mathf.Rad2Deg; } state.angularVelocity = state.reusableRotationVector; } else { if (smoothSync.isSyncingXAngularVelocity) { state.angularVelocity.x = reader.ReadSingle(); } if (smoothSync.isSyncingYAngularVelocity) { state.angularVelocity.y = reader.ReadSingle(); } if (smoothSync.isSyncingZAngularVelocity) { state.angularVelocity.z = reader.ReadSingle(); } } smoothSync.latestReceivedAngularVelocity = state.angularVelocity; } else { // If we didn't receive an updated angular velocity, use the latest received angular velocity. state.angularVelocity = smoothSync.latestReceivedAngularVelocity; } // Update new owner information sent from the Server. if (smoothSync.isSmoothingAuthorityChanges && !NetworkServer.active) { smoothSync.ownerChangeIndicator = (int)reader.ReadByte(); } if (smoothSync.automaticallyResetTime) { state.localTimeResetIndicator = (int)reader.ReadByte(); } return(msg); }
/// <summary> /// Serialize the message over the network. /// </summary> /// <remarks> /// Only sends what it needs and compresses floats if you chose to. /// </remarks> public static void Serialize(this NetworkWriter writer, NetworkStateMirror msg) { bool sendPosition, sendRotation, sendScale, sendVelocity, sendAngularVelocity, sendAtPositionalRestTag, sendAtRotationalRestTag; var smoothSync = msg.smoothSync; var state = msg.state; // If is a server trying to relay client information back out to other clients. if (NetworkServer.active && !smoothSync.hasControl) { sendPosition = state.serverShouldRelayPosition; sendRotation = state.serverShouldRelayRotation; sendScale = state.serverShouldRelayScale; sendVelocity = state.serverShouldRelayVelocity; sendAngularVelocity = state.serverShouldRelayAngularVelocity; sendAtPositionalRestTag = state.atPositionalRest; sendAtRotationalRestTag = state.atRotationalRest; } else // If is a server or client trying to send controlled object information across the network. { sendPosition = smoothSync.sendPosition; sendRotation = smoothSync.sendRotation; sendScale = smoothSync.sendScale; sendVelocity = smoothSync.sendVelocity; sendAngularVelocity = smoothSync.sendAngularVelocity; sendAtPositionalRestTag = smoothSync.sendAtPositionalRestMessage; sendAtRotationalRestTag = smoothSync.sendAtRotationalRestMessage; } // Only set last sync StateMirrors on clients here because the server needs to send multiple Serializes. if (!NetworkServer.active) { if (sendPosition) { smoothSync.lastPositionWhenStateWasSent = state.position; } if (sendRotation) { smoothSync.lastRotationWhenStateWasSent = state.rotation; } if (sendScale) { smoothSync.lastScaleWhenStateWasSent = state.scale; } if (sendVelocity) { smoothSync.lastVelocityWhenStateWasSent = state.velocity; } if (sendAngularVelocity) { smoothSync.lastAngularVelocityWhenStateWasSent = state.angularVelocity; } } writer.WriteByte(encodeSyncInformation(sendPosition, sendRotation, sendScale, sendVelocity, sendAngularVelocity, sendAtPositionalRestTag, sendAtRotationalRestTag)); writer.WriteNetworkIdentity(smoothSync.netID); writer.WriteUInt32((uint)smoothSync.syncIndex); writer.WriteSingle(state.ownerTimestamp); // Write position. if (sendPosition) { if (smoothSync.isPositionCompressed) { if (smoothSync.isSyncingXPosition) { writer.WriteUInt16(HalfHelper.Compress(state.position.x)); } if (smoothSync.isSyncingYPosition) { writer.WriteUInt16(HalfHelper.Compress(state.position.y)); } if (smoothSync.isSyncingZPosition) { writer.WriteUInt16(HalfHelper.Compress(state.position.z)); } } else { if (smoothSync.isSyncingXPosition) { writer.WriteSingle(state.position.x); } if (smoothSync.isSyncingYPosition) { writer.WriteSingle(state.position.y); } if (smoothSync.isSyncingZPosition) { writer.WriteSingle(state.position.z); } } } // Write rotation. if (sendRotation) { Vector3 rot = state.rotation.eulerAngles; if (smoothSync.isRotationCompressed) { // Convert to radians for more accurate Half numbers if (smoothSync.isSyncingXRotation) { writer.WriteUInt16(HalfHelper.Compress(rot.x * Mathf.Deg2Rad)); } if (smoothSync.isSyncingYRotation) { writer.WriteUInt16(HalfHelper.Compress(rot.y * Mathf.Deg2Rad)); } if (smoothSync.isSyncingZRotation) { writer.WriteUInt16(HalfHelper.Compress(rot.z * Mathf.Deg2Rad)); } } else { if (smoothSync.isSyncingXRotation) { writer.WriteSingle(rot.x); } if (smoothSync.isSyncingYRotation) { writer.WriteSingle(rot.y); } if (smoothSync.isSyncingZRotation) { writer.WriteSingle(rot.z); } } } // Write scale. if (sendScale) { if (smoothSync.isScaleCompressed) { if (smoothSync.isSyncingXScale) { writer.WriteUInt16(HalfHelper.Compress(state.scale.x)); } if (smoothSync.isSyncingYScale) { writer.WriteUInt16(HalfHelper.Compress(state.scale.y)); } if (smoothSync.isSyncingZScale) { writer.WriteUInt16(HalfHelper.Compress(state.scale.z)); } } else { if (smoothSync.isSyncingXScale) { writer.WriteSingle(state.scale.x); } if (smoothSync.isSyncingYScale) { writer.WriteSingle(state.scale.y); } if (smoothSync.isSyncingZScale) { writer.WriteSingle(state.scale.z); } } } // Write velocity. if (sendVelocity) { if (smoothSync.isVelocityCompressed) { if (smoothSync.isSyncingXVelocity) { writer.WriteUInt16(HalfHelper.Compress(state.velocity.x)); } if (smoothSync.isSyncingYVelocity) { writer.WriteUInt16(HalfHelper.Compress(state.velocity.y)); } if (smoothSync.isSyncingZVelocity) { writer.WriteUInt16(HalfHelper.Compress(state.velocity.z)); } } else { if (smoothSync.isSyncingXVelocity) { writer.WriteSingle(state.velocity.x); } if (smoothSync.isSyncingYVelocity) { writer.WriteSingle(state.velocity.y); } if (smoothSync.isSyncingZVelocity) { writer.WriteSingle(state.velocity.z); } } } // Write angular velocity. if (sendAngularVelocity) { if (smoothSync.isAngularVelocityCompressed) { // Convert to radians for more accurate Half numbers if (smoothSync.isSyncingXAngularVelocity) { writer.WriteUInt16(HalfHelper.Compress(state.angularVelocity.x * Mathf.Deg2Rad)); } if (smoothSync.isSyncingYAngularVelocity) { writer.WriteUInt16(HalfHelper.Compress(state.angularVelocity.y * Mathf.Deg2Rad)); } if (smoothSync.isSyncingZAngularVelocity) { writer.WriteUInt16(HalfHelper.Compress(state.angularVelocity.z * Mathf.Deg2Rad)); } } else { if (smoothSync.isSyncingXAngularVelocity) { writer.WriteSingle(state.angularVelocity.x); } if (smoothSync.isSyncingYAngularVelocity) { writer.WriteSingle(state.angularVelocity.y); } if (smoothSync.isSyncingZAngularVelocity) { writer.WriteSingle(state.angularVelocity.z); } } } // Only the server sends out owner information. if (smoothSync.isSmoothingAuthorityChanges && NetworkServer.active) { writer.WriteByte((byte)smoothSync.ownerChangeIndicator); } if (smoothSync.automaticallyResetTime) { writer.WriteByte((byte)state.localTimeResetIndicator); } }