using System; using System.IO; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.SceneManagement; namespace Smooth { public class SmoothSyncPUN2 : MonoBehaviourPunCallbacks, IPunObservable, IOnPhotonViewOwnerChange, IPhotonViewCallback { public enum ExtrapolationMode { None = 0, Limited = 1, Unlimited = 2 } public enum WhenToUpdateTransform { Update = 0, FixedUpdate = 1 } public delegate bool validateStateDelegate(StatePUN2 receivedState, StatePUN2 latestVerifiedState); private enum RestState { AT_REST = 0, JUST_STARTED_MOVING = 1, MOVING = 2 } public float interpolationBackTime = 0.12f; public ExtrapolationMode extrapolationMode = ExtrapolationMode.Limited; public bool useExtrapolationTimeLimit = true; public float extrapolationTimeLimit = 5f; public bool useExtrapolationDistanceLimit; public float extrapolationDistanceLimit = 20f; public float sendPositionThreshold; public float sendRotationThreshold; public float sendScaleThreshold; public float sendVelocityThreshold; public float sendAngularVelocityThreshold; public float receivedPositionThreshold; public float receivedRotationThreshold; public float snapPositionThreshold; public float snapRotationThreshold; public float snapScaleThreshold; [Range(0f, 1f)] public float positionLerpSpeed = 0.85f; [Range(0f, 1f)] public float rotationLerpSpeed = 0.85f; [Range(0f, 1f)] public float scaleLerpSpeed = 0.85f; [Range(0f, 5f)] public float timeCorrectionSpeed = 0.1f; public float snapTimeThreshold = 0.3f; public SyncMode syncPosition; public SyncMode syncRotation; public SyncMode syncScale; public SyncMode syncVelocity; public SyncMode syncAngularVelocity; public bool isPositionCompressed; public bool isRotationCompressed; public bool isScaleCompressed; public bool isVelocityCompressed; public bool isAngularVelocityCompressed; public bool automaticallyResetTime = true; private const int maxTimePower = 12; private readonly float maxLocalTime = Mathf.Pow(2f, 12f); private readonly float minTimePrecision = Mathf.Pow(2f, -12f); [NonSerialized] public int localTimeResetIndicator; public bool isSmoothingAuthorityChanges; public WhenToUpdateTransform whenToUpdateTransform; [NonSerialized] public validateStateDelegate validateStateMethod = validateState; private StatePUN2 latestValidatedState; public bool setVelocityInsteadOfPositionOnNonOwners; public bool useLocalTransformOnly; public float maxPositionDifferenceForVelocitySyncing = 10f; [NonSerialized] public StatePUN2[] stateBuffer; [NonSerialized] public int stateCount; [NonSerialized] public Rigidbody rb; [NonSerialized] public bool hasRigidbody; [NonSerialized] public Rigidbody2D rb2D; [NonSerialized] public bool hasRigidbody2D; private bool dontEasePosition; private bool dontEaseRotation; private bool dontEaseScale; private float firstReceivedMessageZeroTime; [NonSerialized] public float lastTimeStateWasSent; [NonSerialized] public Vector3 lastPositionWhenStateWasSent; [NonSerialized] public Quaternion lastRotationWhenStateWasSent = Quaternion.identity; [NonSerialized] public Vector3 lastScaleWhenStateWasSent; [NonSerialized] public Vector3 lastVelocityWhenStateWasSent; [NonSerialized] public Vector3 lastAngularVelocityWhenStateWasSent; [NonSerialized] public GameObject realObjectToSync; [NonSerialized] public bool forceStateSend; [NonSerialized] public bool sendAtPositionalRestMessage; [NonSerialized] public bool sendAtRotationalRestMessage; [NonSerialized] public bool sendPosition; [NonSerialized] public bool sendRotation; [NonSerialized] public bool sendScale; [NonSerialized] public bool sendVelocity; [NonSerialized] public bool sendAngularVelocity; private StatePUN2 targetTempState; private NetworkStatePUN2 sendingTempState; [NonSerialized] public Vector3 latestReceivedVelocity; [NonSerialized] public Vector3 latestReceivedAngularVelocity; private float timeSpentExtrapolating; private bool extrapolatedLastFrame; private Vector3 positionLastAttemptedToSend; private bool changedPositionLastFrame; private Quaternion rotationLastAttemptedToSend; private bool changedRotationLastFrame; private int atRestThresholdCount = 1; private int samePositionCount; private int sameRotationCount; private RestState restStatePosition = RestState.MOVING; private RestState restStateRotation = RestState.MOVING; private StatePUN2 latestEndStateUsed; private bool shouldSendNextPUNUpdate; private Vector3 latestTeleportedFromPosition; private Quaternion latestTeleportedFromRotation; private float latestAuthorityChangeTime; private int previousReceivedOwnerInt; public int ownerChangeIndicator = 1; private bool triedToExtrapolateTooFar; private float lastTimeAttemptedToSend; private float _ownerTime; private float lastTimeOwnerTimeWasSet; public int receivedStatesCounter; public float localTime { get; private set; } public bool isSyncingXPosition { get { if (syncPosition != SyncMode.XYZ && syncPosition != SyncMode.XY && syncPosition != SyncMode.XZ) { return syncPosition == SyncMode.X; } return true; } } public bool isSyncingYPosition { get { if (syncPosition != SyncMode.XYZ && syncPosition != SyncMode.XY && syncPosition != SyncMode.YZ) { return syncPosition == SyncMode.Y; } return true; } } public bool isSyncingZPosition { get { if (syncPosition != SyncMode.XYZ && syncPosition != SyncMode.XZ && syncPosition != SyncMode.YZ) { return syncPosition == SyncMode.Z; } return true; } } public bool isSyncingXRotation { get { if (syncRotation != SyncMode.XYZ && syncRotation != SyncMode.XY && syncRotation != SyncMode.XZ) { return syncRotation == SyncMode.X; } return true; } } public bool isSyncingYRotation { get { if (syncRotation != SyncMode.XYZ && syncRotation != SyncMode.XY && syncRotation != SyncMode.YZ) { return syncRotation == SyncMode.Y; } return true; } } public bool isSyncingZRotation { get { if (syncRotation != SyncMode.XYZ && syncRotation != SyncMode.XZ && syncRotation != SyncMode.YZ) { return syncRotation == SyncMode.Z; } return true; } } public bool isSyncingXScale { get { if (syncScale != SyncMode.XYZ && syncScale != SyncMode.XY && syncScale != SyncMode.XZ) { return syncScale == SyncMode.X; } return true; } } public bool isSyncingYScale { get { if (syncScale != SyncMode.XYZ && syncScale != SyncMode.XY && syncScale != SyncMode.YZ) { return syncScale == SyncMode.Y; } return true; } } public bool isSyncingZScale { get { if (syncScale != SyncMode.XYZ && syncScale != SyncMode.XZ && syncScale != SyncMode.YZ) { return syncScale == SyncMode.Z; } return true; } } public bool isSyncingXVelocity { get { if (syncVelocity != SyncMode.XYZ && syncVelocity != SyncMode.XY && syncVelocity != SyncMode.XZ) { return syncVelocity == SyncMode.X; } return true; } } public bool isSyncingYVelocity { get { if (syncVelocity != SyncMode.XYZ && syncVelocity != SyncMode.XY && syncVelocity != SyncMode.YZ) { return syncVelocity == SyncMode.Y; } return true; } } public bool isSyncingZVelocity { get { if (syncVelocity != SyncMode.XYZ && syncVelocity != SyncMode.XZ && syncVelocity != SyncMode.YZ) { return syncVelocity == SyncMode.Z; } return true; } } public bool isSyncingXAngularVelocity { get { if (syncAngularVelocity != SyncMode.XYZ && syncAngularVelocity != SyncMode.XY && syncAngularVelocity != SyncMode.XZ) { return syncAngularVelocity == SyncMode.X; } return true; } } public bool isSyncingYAngularVelocity { get { if (syncAngularVelocity != SyncMode.XYZ && syncAngularVelocity != SyncMode.XY && syncAngularVelocity != SyncMode.YZ) { return syncAngularVelocity == SyncMode.Y; } return true; } } public bool isSyncingZAngularVelocity { get { if (syncAngularVelocity != SyncMode.XYZ && syncAngularVelocity != SyncMode.XZ && syncAngularVelocity != SyncMode.YZ) { return syncAngularVelocity == SyncMode.Z; } return true; } } public float approximateNetworkTimeOnOwner { get { return _ownerTime + (localTime - lastTimeOwnerTimeWasSet); } set { _ownerTime = value; lastTimeOwnerTimeWasSet = localTime; } } public static bool validateState(StatePUN2 latestReceivedState, StatePUN2 latestValidatedState) { return true; } public void Awake() { int a = ((int)((float)PhotonNetwork.SerializationRate * interpolationBackTime) + 1) * 2; stateBuffer = new StatePUN2[Mathf.Max(a, 30)]; realObjectToSync = base.gameObject; rb = realObjectToSync.GetComponent(); rb2D = realObjectToSync.GetComponent(); if ((bool)rb) { hasRigidbody = true; } else if ((bool)rb2D) { hasRigidbody2D = true; if (syncVelocity != SyncMode.NONE) { syncVelocity = SyncMode.XY; } if (syncAngularVelocity != SyncMode.NONE) { syncAngularVelocity = SyncMode.Z; } } if (!rb && !rb2D) { syncVelocity = SyncMode.NONE; syncAngularVelocity = SyncMode.NONE; } if (extrapolationMode == ExtrapolationMode.Unlimited) { useExtrapolationDistanceLimit = false; useExtrapolationTimeLimit = false; } targetTempState = new StatePUN2(); sendingTempState = new NetworkStatePUN2(); } private void Update() { if (whenToUpdateTransform == WhenToUpdateTransform.Update) { SmoothSyncUpdate(); } } private void FixedUpdate() { if (whenToUpdateTransform == WhenToUpdateTransform.FixedUpdate) { SmoothSyncUpdate(); } } private void SmoothSyncUpdate() { localTime += Time.deltaTime; if (automaticallyResetTime && localTime > maxLocalTime) { ResetLocalTime(); } if (!base.photonView.IsMine) { adjustOwnerTime(); applyInterpolationOrExtrapolation(); } } public override void OnEnable() { base.photonView.AddCallbackTarget(this); SceneManager.sceneLoaded += OnSceneLoaded; if ((bool)base.photonView && base.photonView.IsMine && base.photonView.ViewID > 0) { teleportOwnedObjectFromOwner(); } clearBuffer(); base.OnEnable(); } public override void OnDisable() { base.photonView.RemoveCallbackTarget(this); SceneManager.sceneLoaded -= OnSceneLoaded; base.OnDisable(); } public void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (automaticallyResetTime) { ResetLocalTime(); } } public void ResetLocalTime() { localTimeResetIndicator++; if (localTimeResetIndicator >= 128) { localTimeResetIndicator = 0; } lastTimeStateWasSent -= localTime; lastTimeOwnerTimeWasSet -= localTime; lastTimeAttemptedToSend -= localTime; latestAuthorityChangeTime -= localTime; for (int i = 0; i < stateCount; i++) { stateBuffer[i].receivedTimestamp -= localTime; } localTime = 0f; forceStateSendNextOnPhotonSerializeView(); } public void OnRemoteTimeReset() { approximateNetworkTimeOnOwner -= maxLocalTime; targetTempState.ownerTimestamp -= maxLocalTime; for (int num = stateCount - 1; num >= 0; num--) { stateBuffer[num].ownerTimestamp -= maxLocalTime; } } public override void OnPlayerEnteredRoom(Player newPlayer) { if (base.photonView.IsMine) { base.photonView.RPC("RpcTeleport", newPlayer, getPosition(), getRotation().eulerAngles, getScale(), localTime); } base.OnPlayerEnteredRoom(newPlayer); } private void sendState() { if (!base.photonView.IsMine) { return; } if (syncPosition != SyncMode.NONE) { if (positionLastAttemptedToSend == getPosition()) { if (restStatePosition != RestState.AT_REST) { samePositionCount++; } if (samePositionCount == atRestThresholdCount) { samePositionCount = 0; restStatePosition = RestState.AT_REST; forceStateSendNextOnPhotonSerializeView(); } } else if (restStatePosition == RestState.AT_REST && !almostEqual(getPosition(), latestTeleportedFromPosition, 0.005f)) { restStatePosition = RestState.JUST_STARTED_MOVING; forceStateSendNextOnPhotonSerializeView(); } else if (restStatePosition == RestState.JUST_STARTED_MOVING) { restStatePosition = RestState.MOVING; } else { samePositionCount = 0; } } else { restStatePosition = RestState.AT_REST; } if (syncRotation != SyncMode.NONE) { if (rotationLastAttemptedToSend == getRotation()) { if (restStateRotation != RestState.AT_REST) { sameRotationCount++; } if (sameRotationCount == atRestThresholdCount) { sameRotationCount = 0; restStateRotation = RestState.AT_REST; forceStateSendNextOnPhotonSerializeView(); } } else if (restStateRotation == RestState.AT_REST && getRotation() != latestTeleportedFromRotation) { restStateRotation = RestState.JUST_STARTED_MOVING; forceStateSendNextOnPhotonSerializeView(); } else if (restStateRotation == RestState.JUST_STARTED_MOVING) { restStateRotation = RestState.MOVING; } else { sameRotationCount = 0; } } else { restStateRotation = RestState.AT_REST; } sendPosition = shouldSendPosition(); sendRotation = shouldSendRotation(); sendScale = shouldSendScale(); sendVelocity = shouldSendVelocity(); sendAngularVelocity = shouldSendAngularVelocity(); if (!sendPosition && !sendRotation && !sendScale && !sendVelocity && !sendAngularVelocity) { return; } sendingTempState.copyFromSmoothSync(this); if (restStatePosition == RestState.AT_REST) { sendAtPositionalRestMessage = true; } if (restStateRotation == RestState.AT_REST) { sendAtRotationalRestMessage = true; } if (restStatePosition == RestState.JUST_STARTED_MOVING) { sendingTempState.state.position = lastPositionWhenStateWasSent; } if (restStateRotation == RestState.JUST_STARTED_MOVING) { sendingTempState.state.rotation = lastRotationWhenStateWasSent; } if (restStatePosition == RestState.JUST_STARTED_MOVING || restStateRotation == RestState.JUST_STARTED_MOVING) { sendingTempState.state.ownerTimestamp = lastTimeAttemptedToSend; if (restStatePosition != RestState.JUST_STARTED_MOVING) { sendingTempState.state.position = positionLastAttemptedToSend; } if (restStateRotation != RestState.JUST_STARTED_MOVING) { sendingTempState.state.rotation = rotationLastAttemptedToSend; } } lastTimeStateWasSent = localTime; shouldSendNextPUNUpdate = true; } public void OnOwnerChange(Player newOwner, Player previousOwner) { if (isSmoothingAuthorityChanges && newOwner == PhotonNetwork.LocalPlayer && stateBuffer[0] != null) { ownerChangeIndicator++; if (ownerChangeIndicator > 127) { ownerChangeIndicator = 1; } if (hasRigidbody) { rb.velocity = stateBuffer[0].velocity; rb.angularVelocity = stateBuffer[0].angularVelocity; } else if (hasRigidbody2D) { rb2D.velocity = stateBuffer[0].velocity; rb2D.angularVelocity = stateBuffer[0].angularVelocity.z; } clearBuffer(); } } public void checkIfOwnerHasChanged(StatePUN2 newState) { if (isSmoothingAuthorityChanges && ownerChangeIndicator != previousReceivedOwnerInt) { approximateNetworkTimeOnOwner = newState.ownerTimestamp; latestAuthorityChangeTime = localTime; stateCount = 0; firstReceivedMessageZeroTime = 1f; restStatePosition = RestState.MOVING; restStateRotation = RestState.MOVING; StatePUN2 statePUN = new StatePUN2(); statePUN.position = getPosition(); statePUN.rotation = getRotation(); statePUN.scale = getScale(); statePUN.ownerTimestamp = newState.ownerTimestamp - interpolationBackTime; statePUN.receivedTimestamp = newState.receivedTimestamp; addState(statePUN); previousReceivedOwnerInt = ownerChangeIndicator; } } private void applyInterpolationOrExtrapolation() { if (stateCount == 0) { return; } if (!extrapolatedLastFrame) { targetTempState.resetTheVariables(); } triedToExtrapolateTooFar = false; float num = approximateNetworkTimeOnOwner - interpolationBackTime; if (stateCount > 1 && stateBuffer[0].ownerTimestamp > num) { interpolate(num); extrapolatedLastFrame = false; } else if (stateBuffer[0].teleport) { targetTempState.copyFromState(stateBuffer[0]); stopEasing(); extrapolatedLastFrame = false; } else if (stateBuffer[0].atPositionalRest && stateBuffer[0].atRotationalRest) { targetTempState.copyFromState(stateBuffer[0]); extrapolatedLastFrame = false; if (setVelocityInsteadOfPositionOnNonOwners) { triedToExtrapolateTooFar = true; } } else if (!isSmoothingAuthorityChanges || Time.realtimeSinceStartup - latestAuthorityChangeTime > interpolationBackTime * 2f) { bool flag = extrapolate(num); extrapolatedLastFrame = true; triedToExtrapolateTooFar = !flag; if (setVelocityInsteadOfPositionOnNonOwners) { float num2 = num - stateBuffer[0].ownerTimestamp; targetTempState.velocity = stateBuffer[0].velocity; targetTempState.position = stateBuffer[0].position + targetTempState.velocity * num2; Vector3 vector = base.transform.position + targetTempState.velocity * Time.deltaTime; float t = (targetTempState.position - vector).sqrMagnitude / (maxPositionDifferenceForVelocitySyncing * maxPositionDifferenceForVelocitySyncing); targetTempState.velocity = Vector3.Lerp(targetTempState.velocity, (targetTempState.position - base.transform.position) / Time.deltaTime, t); } } float t2 = positionLerpSpeed; float t3 = rotationLerpSpeed; float t4 = scaleLerpSpeed; bool flag2 = false; bool isTeleporting = false; if (dontEasePosition) { t2 = 1f; flag2 = true; dontEasePosition = false; } if (dontEaseRotation) { t3 = 1f; isTeleporting = true; dontEaseRotation = false; } if (dontEaseScale) { t4 = 1f; dontEaseScale = false; } if (!triedToExtrapolateTooFar) { bool flag3 = false; float num3 = 0f; if (getPosition() != targetTempState.position && receivedPositionThreshold != 0f) { num3 = Vector3.Distance(getPosition(), targetTempState.position); } if (receivedPositionThreshold != 0f) { if (num3 > receivedPositionThreshold) { flag3 = true; } } else { flag3 = true; } bool flag4 = false; float num4 = 0f; if (getRotation() != targetTempState.rotation && receivedRotationThreshold != 0f) { num4 = Quaternion.Angle(getRotation(), targetTempState.rotation); } if (receivedRotationThreshold != 0f) { if (num4 > receivedRotationThreshold) { flag4 = true; } } else { flag4 = true; } bool flag5 = false; if (getScale() != targetTempState.scale) { flag5 = true; } if (hasRigidbody && !rb.isKinematic) { rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } else if (hasRigidbody2D && !rb2D.isKinematic) { rb2D.velocity = Vector2.zero; rb2D.angularVelocity = 0f; } if (syncPosition != SyncMode.NONE && flag3) { Vector3 position = getPosition(); if (isSyncingXPosition) { position.x = targetTempState.position.x; } if (isSyncingYPosition) { position.y = targetTempState.position.y; } if (isSyncingZPosition) { position.z = targetTempState.position.z; } if (setVelocityInsteadOfPositionOnNonOwners && !flag2) { if (hasRigidbody) { rb.velocity = targetTempState.velocity; } if (hasRigidbody2D) { rb2D.velocity = targetTempState.velocity; } } else { setPosition(Vector3.Lerp(getPosition(), position, t2), flag2); } } if (syncRotation != SyncMode.NONE && flag4) { Vector3 eulerAngles = getRotation().eulerAngles; if (isSyncingXRotation) { eulerAngles.x = targetTempState.rotation.eulerAngles.x; } if (isSyncingYRotation) { eulerAngles.y = targetTempState.rotation.eulerAngles.y; } if (isSyncingZRotation) { eulerAngles.z = targetTempState.rotation.eulerAngles.z; } Quaternion b = Quaternion.Euler(eulerAngles); setRotation(Quaternion.Lerp(getRotation(), b, t3), isTeleporting); } if (syncScale != SyncMode.NONE && flag5) { Vector3 scale = getScale(); if (isSyncingXScale) { scale.x = targetTempState.scale.x; } if (isSyncingYScale) { scale.y = targetTempState.scale.y; } if (isSyncingZScale) { scale.z = targetTempState.scale.z; } setScale(Vector3.Lerp(getScale(), scale, t4)); } } else if (triedToExtrapolateTooFar) { if (hasRigidbody) { rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } if (hasRigidbody2D) { rb2D.velocity = Vector2.zero; rb2D.angularVelocity = 0f; } } } private void interpolate(float interpolationTime) { int i; for (i = 0; i < stateCount && !(stateBuffer[i].ownerTimestamp <= interpolationTime); i++) { } if (i == stateCount) { i--; } StatePUN2 end = stateBuffer[Mathf.Max(i - 1, 0)]; StatePUN2 statePUN = stateBuffer[i]; float t = (interpolationTime - statePUN.ownerTimestamp) / (end.ownerTimestamp - statePUN.ownerTimestamp); shouldTeleport(statePUN, ref end, interpolationTime, ref t); targetTempState = StatePUN2.Lerp(targetTempState, statePUN, end, t); if (snapPositionThreshold != 0f) { if ((end.position - statePUN.position).magnitude > snapPositionThreshold) { targetTempState.position = end.position; } dontEasePosition = true; } if (snapScaleThreshold != 0f) { if ((end.scale - statePUN.scale).magnitude > snapScaleThreshold) { targetTempState.scale = end.scale; } dontEaseScale = true; } if (snapRotationThreshold != 0f) { if (Quaternion.Angle(end.rotation, statePUN.rotation) > snapRotationThreshold) { targetTempState.rotation = end.rotation; } dontEaseRotation = true; } if (setVelocityInsteadOfPositionOnNonOwners) { Vector3 vector = base.transform.position + targetTempState.velocity * Time.deltaTime; float t2 = (targetTempState.position - vector).sqrMagnitude / (maxPositionDifferenceForVelocitySyncing * maxPositionDifferenceForVelocitySyncing); targetTempState.velocity = Vector3.Lerp(targetTempState.velocity, (targetTempState.position - base.transform.position) / Time.deltaTime, t2); } } private bool extrapolate(float interpolationTime) { if (!extrapolatedLastFrame || targetTempState.ownerTimestamp < stateBuffer[0].ownerTimestamp) { targetTempState.copyFromState(stateBuffer[0]); timeSpentExtrapolating = 0f; } if (extrapolationMode != ExtrapolationMode.None && stateCount >= 2) { if (syncVelocity == SyncMode.NONE && !stateBuffer[0].atPositionalRest) { bool flag = false; for (int i = 1; i < stateCount; i++) { if (stateBuffer[0].ownerTimestamp != stateBuffer[i].ownerTimestamp) { targetTempState.velocity = (stateBuffer[0].position - stateBuffer[i].position) / (stateBuffer[0].ownerTimestamp - stateBuffer[i].ownerTimestamp); flag = true; break; } } if (!flag) { targetTempState.velocity = Vector3.zero; } } if (syncAngularVelocity == SyncMode.NONE && !stateBuffer[0].atRotationalRest) { bool flag2 = false; for (int j = 1; j < stateCount; j++) { if (stateBuffer[0].ownerTimestamp != stateBuffer[j].ownerTimestamp) { Quaternion quaternion = stateBuffer[0].rotation * Quaternion.Inverse(stateBuffer[j].rotation); Vector3 angularVelocity = new Vector3(Mathf.DeltaAngle(0f, quaternion.eulerAngles.x), Mathf.DeltaAngle(0f, quaternion.eulerAngles.y), Mathf.DeltaAngle(0f, quaternion.eulerAngles.z)) / (stateBuffer[0].ownerTimestamp - stateBuffer[j].ownerTimestamp); targetTempState.angularVelocity = angularVelocity; flag2 = true; break; } } if (!flag2) { targetTempState.angularVelocity = Vector3.zero; } } } if (extrapolationMode == ExtrapolationMode.None) { return false; } if (useExtrapolationTimeLimit && timeSpentExtrapolating > extrapolationTimeLimit) { return false; } bool flag3 = Mathf.Abs(targetTempState.velocity.x) >= 0.01f || Mathf.Abs(targetTempState.velocity.y) >= 0.01f || Mathf.Abs(targetTempState.velocity.z) >= 0.01f; bool flag4 = Mathf.Abs(targetTempState.angularVelocity.x) >= 0.01f || Mathf.Abs(targetTempState.angularVelocity.y) >= 0.01f || Mathf.Abs(targetTempState.angularVelocity.z) >= 0.01f; if (!flag3 && !flag4) { return false; } float num = 0f; num = ((timeSpentExtrapolating != 0f) ? Time.deltaTime : (interpolationTime - targetTempState.ownerTimestamp)); timeSpentExtrapolating += num; if (flag3) { targetTempState.position += targetTempState.velocity * num; if (Mathf.Abs(targetTempState.velocity.y) >= 0.01f) { if (hasRigidbody && rb.useGravity) { targetTempState.velocity += Physics.gravity * num; } else if (hasRigidbody2D) { targetTempState.velocity += Physics.gravity * rb2D.gravityScale * num; } } if (hasRigidbody) { targetTempState.velocity -= targetTempState.velocity * num * rb.drag; } else if (hasRigidbody2D) { targetTempState.velocity -= targetTempState.velocity * num * rb2D.drag; } } if (flag4) { Quaternion quaternion2 = Quaternion.AngleAxis(num * targetTempState.angularVelocity.magnitude, targetTempState.angularVelocity); targetTempState.rotation = quaternion2 * targetTempState.rotation; float num2 = 0f; if (hasRigidbody) { num2 = rb.angularDrag; } if (hasRigidbody2D) { num2 = rb2D.angularDrag; } if ((hasRigidbody || hasRigidbody2D) && num2 > 0f) { targetTempState.angularVelocity -= targetTempState.angularVelocity * num * num2; } } if (useExtrapolationDistanceLimit && Vector3.Distance(stateBuffer[0].position, targetTempState.position) >= extrapolationDistanceLimit) { return false; } return true; } private void shouldTeleport(StatePUN2 start, ref StatePUN2 end, float interpolationTime, ref float t) { if (start.ownerTimestamp > interpolationTime && start.teleport && stateCount == 2) { end = start; t = 1f; stopEasing(); } for (int i = 0; i < stateCount; i++) { if (stateBuffer[i] != latestEndStateUsed || latestEndStateUsed == end || latestEndStateUsed == start) { continue; } for (int num = i - 1; num >= 0; num--) { if (stateBuffer[num].teleport) { t = 1f; stopEasing(); } if (stateBuffer[num] == start) { break; } } break; } latestEndStateUsed = end; if (end.teleport) { t = 1f; stopEasing(); } } public Vector3 getPosition() { if (useLocalTransformOnly) { return realObjectToSync.transform.localPosition; } return realObjectToSync.transform.position; } public Quaternion getRotation() { if (useLocalTransformOnly) { return realObjectToSync.transform.localRotation; } return realObjectToSync.transform.rotation; } public Vector3 getScale() { return realObjectToSync.transform.localScale; } public void setPosition(Vector3 position, bool isTeleporting) { if (position.x != float.NaN && position.y != float.NaN && position.z != float.NaN && !float.IsInfinity(position.x) && !float.IsInfinity(position.y) && !float.IsInfinity(position.z)) { if (useLocalTransformOnly) { realObjectToSync.transform.localPosition = position; } else if (hasRigidbody && !isTeleporting && whenToUpdateTransform == WhenToUpdateTransform.FixedUpdate) { rb.MovePosition(position); } else if (hasRigidbody2D && !isTeleporting && whenToUpdateTransform == WhenToUpdateTransform.FixedUpdate) { rb2D.MovePosition(position); } else { realObjectToSync.transform.position = position; } } } public void setRotation(Quaternion rotation, bool isTeleporting) { if (rotation.x != float.NaN && rotation.y != float.NaN && rotation.z != float.NaN && rotation.w != float.NaN && !float.IsInfinity(rotation.x) && !float.IsInfinity(rotation.y) && !float.IsInfinity(rotation.z) && !float.IsInfinity(rotation.w)) { if (useLocalTransformOnly) { realObjectToSync.transform.localRotation = rotation; } else if (hasRigidbody && !isTeleporting && whenToUpdateTransform == WhenToUpdateTransform.FixedUpdate) { rb.MoveRotation(rotation); } else if (hasRigidbody2D && !isTeleporting && whenToUpdateTransform == WhenToUpdateTransform.FixedUpdate) { rb2D.MoveRotation(rotation.eulerAngles.z); } else { realObjectToSync.transform.rotation = rotation; } } } public void setScale(Vector3 scale) { realObjectToSync.transform.localScale = scale; } private void resetFlags() { forceStateSend = false; sendAtPositionalRestMessage = false; sendAtRotationalRestMessage = false; } private bool almostEqual(Vector3 v1, Vector3 v2, float precision) { bool result = true; if (Mathf.Abs(v1.x - v2.x) > precision) { result = false; } if (Mathf.Abs(v1.y - v2.y) > precision) { result = false; } if (Mathf.Abs(v1.z - v2.z) > precision) { result = false; } return result; } public void addState(StatePUN2 state) { if (latestValidatedState != null && !validateStateMethod(state, latestValidatedState)) { return; } latestValidatedState = state; if (stateCount > 1) { bool num = state.ownerTimestamp - stateBuffer[0].ownerTimestamp <= 0f; bool flag = state.localTimeResetIndicator != stateBuffer[0].localTimeResetIndicator; if (num && !flag) { return; } if (flag) { OnRemoteTimeReset(); } } for (int num2 = stateBuffer.Length - 1; num2 >= 1; num2--) { stateBuffer[num2] = stateBuffer[num2 - 1]; } stateBuffer[0] = state; stateCount = Mathf.Min(stateCount + 1, stateBuffer.Length); } public void stopEasing() { dontEasePosition = true; dontEaseRotation = true; dontEaseScale = true; } public void clearBuffer() { base.photonView.RPC("RpcClearBuffer", RpcTarget.All); } [PunRPC] public void RpcClearBuffer() { stateCount = 0; firstReceivedMessageZeroTime = 0f; restStatePosition = RestState.MOVING; restStateRotation = RestState.MOVING; } public void teleport() { teleportOwnedObjectFromOwner(); } public void teleportOwnedObjectFromOwner() { if (PhotonNetwork.IsConnected) { if (!base.photonView.IsMine) { Debug.LogWarning("Should only call teleportOwnedObjectFromOwner() on owned objects."); return; } latestTeleportedFromPosition = getPosition(); latestTeleportedFromRotation = getRotation(); base.photonView.RPC("RpcTeleport", RpcTarget.Others, getPosition(), getRotation().eulerAngles, getScale(), localTime); } } public void teleportAnyObject(Vector3 newPosition, Quaternion newRotation, Vector3 newScale) { if (PhotonNetwork.IsConnected) { if (base.photonView.IsMine) { setPosition(newPosition, isTeleporting: true); setRotation(newRotation, isTeleporting: true); setScale(newScale); teleportOwnedObjectFromOwner(); } if (!base.photonView.IsMine) { base.photonView.RPC("RpcNonServerOwnedTeleportFromServer", RpcTarget.Others, newPosition, newRotation.eulerAngles, newScale); } } } [PunRPC] public void RpcNonServerOwnedTeleportFromServer(Vector3 newPosition, Vector3 newRotation, Vector3 newScale) { if (base.photonView.IsMine) { setPosition(newPosition, isTeleporting: true); setRotation(Quaternion.Euler(newRotation), isTeleporting: true); setScale(newScale); teleportOwnedObjectFromOwner(); } } [PunRPC] public void RpcTeleport(Vector3 position, Vector3 rotation, Vector3 scale, float tempOwnerTime) { StatePUN2 statePUN = new StatePUN2(); statePUN.copyFromSmoothSync(this); statePUN.position = position; statePUN.rotation = Quaternion.Euler(rotation); statePUN.ownerTimestamp = tempOwnerTime; statePUN.receivedTimestamp = localTime; statePUN.teleport = true; addTeleportState(statePUN); } private void addTeleportState(StatePUN2 teleportState) { if (teleportState != null) { teleportState.atPositionalRest = true; teleportState.atRotationalRest = true; } if (stateCount == 0) { approximateNetworkTimeOnOwner = teleportState.ownerTimestamp; } if (stateCount == 0 || teleportState.ownerTimestamp >= stateBuffer[0].ownerTimestamp) { for (int num = stateBuffer.Length - 1; num >= 1; num--) { stateBuffer[num] = stateBuffer[num - 1]; } stateBuffer[0] = teleportState; } else { if (stateCount == stateBuffer.Length && stateBuffer[stateCount - 1].ownerTimestamp > teleportState.ownerTimestamp) { return; } for (int num2 = stateCount - 1; num2 >= 0; num2--) { if (stateBuffer[num2].ownerTimestamp > teleportState.ownerTimestamp) { for (int num3 = stateBuffer.Length - 1; num3 > num2 + 1; num3--) { stateBuffer[num3] = stateBuffer[num3 - 1]; } stateBuffer[num2 + 1] = teleportState; break; } } } stateCount = Mathf.Min(stateCount + 1, stateBuffer.Length); } public void forceStateSendNextOnPhotonSerializeView() { forceStateSend = true; } public bool shouldSendPosition() { if (syncPosition != SyncMode.NONE && (forceStateSend || (getPosition() != lastPositionWhenStateWasSent && (sendPositionThreshold == 0f || Vector3.Distance(lastPositionWhenStateWasSent, getPosition()) > sendPositionThreshold)))) { return true; } return false; } public bool shouldSendRotation() { if (syncRotation != SyncMode.NONE && (forceStateSend || (getRotation() != lastRotationWhenStateWasSent && (sendRotationThreshold == 0f || Quaternion.Angle(lastRotationWhenStateWasSent, getRotation()) > sendRotationThreshold)))) { return true; } return false; } public bool shouldSendScale() { if (syncScale != SyncMode.NONE && (forceStateSend || (getScale() != lastScaleWhenStateWasSent && (sendScaleThreshold == 0f || Vector3.Distance(lastScaleWhenStateWasSent, getScale()) > sendScaleThreshold)))) { return true; } return false; } public bool shouldSendVelocity() { if (hasRigidbody) { if (syncVelocity != SyncMode.NONE && (forceStateSend || (rb.velocity != lastVelocityWhenStateWasSent && (sendVelocityThreshold == 0f || Vector3.Distance(lastVelocityWhenStateWasSent, rb.velocity) > sendVelocityThreshold)))) { return true; } return false; } if (hasRigidbody2D) { if (syncVelocity != SyncMode.NONE && (forceStateSend || ((rb2D.velocity.x != lastVelocityWhenStateWasSent.x || rb2D.velocity.y != lastVelocityWhenStateWasSent.y) && (sendVelocityThreshold == 0f || Vector2.Distance(lastVelocityWhenStateWasSent, rb2D.velocity) > sendVelocityThreshold)))) { return true; } return false; } return false; } public bool shouldSendAngularVelocity() { if (hasRigidbody) { if (syncAngularVelocity != SyncMode.NONE && (forceStateSend || (rb.angularVelocity != lastAngularVelocityWhenStateWasSent && (sendAngularVelocityThreshold == 0f || Vector3.Distance(lastAngularVelocityWhenStateWasSent, rb.angularVelocity * 57.29578f) > sendAngularVelocityThreshold)))) { return true; } return false; } if (hasRigidbody2D) { if (syncAngularVelocity != SyncMode.NONE && (forceStateSend || (rb2D.angularVelocity != lastAngularVelocityWhenStateWasSent.z && (sendAngularVelocityThreshold == 0f || Mathf.Abs(lastAngularVelocityWhenStateWasSent.z - rb2D.angularVelocity) > sendAngularVelocityThreshold)))) { return true; } return false; } return false; } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if (stream.IsWriting) { sendState(); stream.SendNext(shouldSendNextPUNUpdate); if (shouldSendNextPUNUpdate) { using (MemoryStream memoryStream = new MemoryStream()) { BinaryWriter writer = new BinaryWriter(memoryStream); sendingTempState.Serialize(writer); stream.SendNext(memoryStream.ToArray()); } shouldSendNextPUNUpdate = false; } positionLastAttemptedToSend = getPosition(); rotationLastAttemptedToSend = getRotation(); lastTimeAttemptedToSend = localTime; resetFlags(); } else if ((bool)stream.ReceiveNext()) { NetworkStatePUN2 networkStatePUN = new NetworkStatePUN2(this); using (MemoryStream input = new MemoryStream((byte[])stream.ReceiveNext())) { BinaryReader reader = new BinaryReader(input); networkStatePUN.Deserialize(reader, this); } if (networkStatePUN != null && !base.photonView.IsMine) { networkStatePUN.smoothSync.checkIfOwnerHasChanged(networkStatePUN.state); networkStatePUN.smoothSync.addState(networkStatePUN.state); } } } private void adjustOwnerTime() { if (stateBuffer[0] != null && (!stateBuffer[0].atPositionalRest || !stateBuffer[0].atRotationalRest)) { float num = stateBuffer[0].ownerTimestamp + (localTime - stateBuffer[0].receivedTimestamp); float num2 = Mathf.Max(timeCorrectionSpeed * Time.deltaTime, minTimePrecision); if (firstReceivedMessageZeroTime == 0f) { firstReceivedMessageZeroTime = localTime; } float num3 = Mathf.Abs(approximateNetworkTimeOnOwner - num); if (receivedStatesCounter < PhotonNetwork.SerializationRate || num3 < num2 || num3 > snapTimeThreshold) { approximateNetworkTimeOnOwner = num; } else if (approximateNetworkTimeOnOwner < num) { approximateNetworkTimeOnOwner += num2; } else { approximateNetworkTimeOnOwner -= num2; } } } } }