1529 lines
38 KiB
C#
1529 lines
38 KiB
C#
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<Rigidbody>();
|
|
rb2D = realObjectToSync.GetComponent<Rigidbody2D>();
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|