上传YomovSDK
This commit is contained in:
@@ -0,0 +1,441 @@
|
||||
using FishNet.Component.Prediction;
|
||||
using FishNet.Managing;
|
||||
using FishNet.Managing.Timing;
|
||||
using FishNet.Object.Prediction;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Object
|
||||
{
|
||||
#if PREDICTION_V2
|
||||
public partial class NetworkObject : MonoBehaviour
|
||||
{
|
||||
|
||||
#region Types.
|
||||
#if PREDICTION_V2
|
||||
/// <summary>
|
||||
/// Type of prediction movement being used.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
internal enum PredictionType : byte
|
||||
{
|
||||
Other = 0,
|
||||
Rigidbody = 1,
|
||||
Rigidbody2D = 2
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Last tick this object replicated.
|
||||
/// </summary>
|
||||
internal EstimatedTick ReplicateTick;
|
||||
/// <summary>
|
||||
/// Last tick to replicate even if out of order. This could be from tick events or even replaying inputs.
|
||||
/// </summary>
|
||||
internal uint LastUnorderedReplicateTick;
|
||||
#endregion
|
||||
|
||||
#region Internal.
|
||||
/// <summary>
|
||||
/// Pauses rigidbodies for prediction.
|
||||
/// </summary>
|
||||
internal RigidbodyPauser RigidbodyPauser;
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
#region Preset SmoothingDatas.
|
||||
private static AdaptiveInterpolationSmoothingData _accurateSmoothingData = new AdaptiveInterpolationSmoothingData()
|
||||
{
|
||||
InterpolationPercent = 0.5f,
|
||||
CollisionInterpolationPercent = 0.05f,
|
||||
InterpolationDecreaseStep = 1,
|
||||
InterpolationIncreaseStep = 2,
|
||||
};
|
||||
private static AdaptiveInterpolationSmoothingData _mixedSmoothingData = new AdaptiveInterpolationSmoothingData()
|
||||
{
|
||||
InterpolationPercent = 1f,
|
||||
CollisionInterpolationPercent = 0.1f,
|
||||
InterpolationDecreaseStep = 1,
|
||||
InterpolationIncreaseStep = 3,
|
||||
};
|
||||
private static AdaptiveInterpolationSmoothingData _gradualSmoothingData = new AdaptiveInterpolationSmoothingData()
|
||||
{
|
||||
InterpolationPercent = 1.5f,
|
||||
CollisionInterpolationPercent = 0.2f,
|
||||
InterpolationDecreaseStep = 1,
|
||||
InterpolationIncreaseStep = 5,
|
||||
};
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Graphical smoother to use when using set for owner.
|
||||
/// </summary>
|
||||
private SetInterpolationSmoother _ownerSetInterpolationSmoother;
|
||||
/// <summary>
|
||||
/// Graphical smoother to use when using set for spectators.
|
||||
/// </summary>
|
||||
private SetInterpolationSmoother _spectatorSetInterpolationSmoother;
|
||||
/// <summary>
|
||||
/// Graphical smoother to use when using adaptive.
|
||||
/// </summary>
|
||||
private AdaptiveInterpolationSmootherFixed _spectatorAdaptiveInterpolationSmoother;
|
||||
/// <summary>
|
||||
/// NetworkBehaviours which use prediction.
|
||||
/// </summary>
|
||||
private List<NetworkBehaviour> _predictionBehaviours = new List<NetworkBehaviour>();
|
||||
/// <summary>
|
||||
/// Tick when CollionStayed last called. This only has value if using prediction.
|
||||
/// </summary>
|
||||
private uint _collisionStayedTick;
|
||||
/// <summary>
|
||||
/// Local client objects this object is currently colliding with.
|
||||
/// </summary>
|
||||
private HashSet<GameObject> _localClientCollidedObjects = new HashSet<GameObject>();
|
||||
#endregion
|
||||
|
||||
private void InitializeSmoothers()
|
||||
{
|
||||
bool usesRb = (_predictionType == PredictionType.Rigidbody);
|
||||
bool usesRb2d = (_predictionType == PredictionType.Rigidbody2D);
|
||||
if (usesRb || usesRb2d)
|
||||
{
|
||||
RigidbodyPauser = new RigidbodyPauser();
|
||||
RigidbodyType rbType = (usesRb) ? RigidbodyType.Rigidbody : RigidbodyType.Rigidbody2D;
|
||||
RigidbodyPauser.UpdateRigidbodies(transform, rbType, true, _graphicalObject);
|
||||
}
|
||||
|
||||
//Create SetInterpolation smoother.
|
||||
_ownerSetInterpolationSmoother = new SetInterpolationSmoother();
|
||||
float teleportThreshold = (_enableTeleport) ? _ownerTeleportThreshold : MoveRatesCls.UNSET_VALUE;
|
||||
SetInterpolationSmootherData osd = new SetInterpolationSmootherData()
|
||||
{
|
||||
GraphicalObject = _graphicalObject,
|
||||
Interpolation = _ownerInterpolation,
|
||||
SmoothPosition = true,
|
||||
SmoothRotation = true,
|
||||
SmoothScale = true,
|
||||
NetworkObject = this,
|
||||
TeleportThreshold = teleportThreshold,
|
||||
};
|
||||
_ownerSetInterpolationSmoother.InitializeOnce(osd);
|
||||
|
||||
//Spectator.
|
||||
_spectatorSetInterpolationSmoother = new SetInterpolationSmoother();
|
||||
_spectatorSetInterpolationSmoother.InitializeOnce(osd);
|
||||
|
||||
//Create adaptive interpolation smoother if enabled.
|
||||
if (_spectatorAdaptiveInterpolation)
|
||||
{
|
||||
_spectatorAdaptiveInterpolationSmoother = new AdaptiveInterpolationSmootherFixed();
|
||||
//Smoothing values.
|
||||
AdaptiveInterpolationSmoothingData aisd;
|
||||
if (_adaptiveSmoothingType == AdaptiveSmoothingType.Custom)
|
||||
aisd = _customSmoothingData;
|
||||
else
|
||||
aisd = _preconfiguredSmoothingDataPreview;
|
||||
|
||||
//Other details.
|
||||
aisd.GraphicalObject = _graphicalObject;
|
||||
aisd.SmoothPosition = true;
|
||||
aisd.SmoothRotation = true;
|
||||
aisd.SmoothScale = true;
|
||||
aisd.NetworkObject = this;
|
||||
aisd.TeleportThreshold = teleportThreshold;
|
||||
_spectatorAdaptiveInterpolationSmoother.Initialize(aisd);
|
||||
}
|
||||
}
|
||||
|
||||
private void Prediction_Update()
|
||||
{
|
||||
if (!_enablePrediction)
|
||||
return;
|
||||
|
||||
_ownerSetInterpolationSmoother.Update();
|
||||
if (IsHost)
|
||||
_spectatorSetInterpolationSmoother.Update();
|
||||
else
|
||||
_spectatorAdaptiveInterpolationSmoother?.Update();
|
||||
}
|
||||
|
||||
private void TimeManager_OnPreTick()
|
||||
{
|
||||
//Do not need to check use prediction because this method only fires if prediction is on for this object.
|
||||
_ownerSetInterpolationSmoother.OnPreTick();
|
||||
if (IsHost)
|
||||
_spectatorSetInterpolationSmoother.OnPreTick();
|
||||
else
|
||||
_spectatorAdaptiveInterpolationSmoother?.OnPreTick();
|
||||
}
|
||||
private void TimeManager_OnPostTick()
|
||||
{
|
||||
//Do not need to check use prediction because this method only fires if prediction is on for this object.
|
||||
_ownerSetInterpolationSmoother.OnPostTick();
|
||||
if (IsHost)
|
||||
_spectatorSetInterpolationSmoother.OnPostTick();
|
||||
else
|
||||
_spectatorAdaptiveInterpolationSmoother?.OnPostTick();
|
||||
|
||||
TrySetCollisionExited();
|
||||
}
|
||||
|
||||
private void Prediction_Preinitialize(NetworkManager manager, bool asServer)
|
||||
{
|
||||
if (!_enablePrediction)
|
||||
return;
|
||||
|
||||
InitializeSmoothers();
|
||||
|
||||
if (asServer)
|
||||
return;
|
||||
|
||||
if (_predictionBehaviours.Count > 0)
|
||||
{
|
||||
manager.PredictionManager.OnPreReconcile += PredictionManager_OnPreReconcile;
|
||||
manager.PredictionManager.OnReplicateReplay += PredictionManager_OnReplicateReplay;
|
||||
manager.PredictionManager.OnPostReconcile += PredictionManager_OnPostReconcile;
|
||||
if (_spectatorAdaptiveInterpolationSmoother != null)
|
||||
{
|
||||
manager.PredictionManager.OnPreReplicateReplay += PredictionManager_OnPreReplicateReplay;
|
||||
manager.PredictionManager.OnPostReplicateReplay += PredictionManager_OnPostReplicateReplay;
|
||||
}
|
||||
manager.TimeManager.OnPreTick += TimeManager_OnPreTick;
|
||||
manager.TimeManager.OnPostTick += TimeManager_OnPostTick;
|
||||
}
|
||||
}
|
||||
|
||||
private void Prediction_Deinitialize(bool asServer)
|
||||
{
|
||||
if (!_enablePrediction)
|
||||
return;
|
||||
|
||||
/* Only the client needs to unsubscribe from these but
|
||||
* asServer may not invoke as false if the client is suddenly
|
||||
* dropping their connection. */
|
||||
if (_predictionBehaviours.Count > 0 && NetworkManager != null)
|
||||
{
|
||||
NetworkManager.PredictionManager.OnPreReconcile -= PredictionManager_OnPreReconcile;
|
||||
NetworkManager.PredictionManager.OnReplicateReplay -= PredictionManager_OnReplicateReplay;
|
||||
NetworkManager.PredictionManager.OnPostReconcile -= PredictionManager_OnPostReconcile;
|
||||
if (_spectatorAdaptiveInterpolationSmoother != null)
|
||||
{
|
||||
NetworkManager.PredictionManager.OnPreReplicateReplay -= PredictionManager_OnPreReplicateReplay;
|
||||
NetworkManager.PredictionManager.OnPostReplicateReplay -= PredictionManager_OnPostReplicateReplay;
|
||||
}
|
||||
NetworkManager.TimeManager.OnPreTick -= TimeManager_OnPreTick;
|
||||
NetworkManager.TimeManager.OnPostTick -= TimeManager_OnPostTick;
|
||||
}
|
||||
}
|
||||
|
||||
private void PredictionManager_OnPreReconcile(uint clientReconcileTick, uint serverReconcileTick)
|
||||
{
|
||||
for (int i = 0; i < _predictionBehaviours.Count; i++)
|
||||
_predictionBehaviours[i].Reconcile_Client_Start();
|
||||
}
|
||||
|
||||
private void PredictionManager_OnPostReconcile(uint clientReconcileTick, uint serverReconcileTick)
|
||||
{
|
||||
_spectatorAdaptiveInterpolationSmoother?.OnPostReconcile(clientReconcileTick, serverReconcileTick);
|
||||
|
||||
for (int i = 0; i < _predictionBehaviours.Count; i++)
|
||||
_predictionBehaviours[i].Reconcile_Client_End();
|
||||
|
||||
/* Unpause rigidbody pauser. It's okay to do that here rather
|
||||
* than per NB, where the pausing occurs, because once here
|
||||
* the entire object is out of the replay cycle so there's
|
||||
* no reason to try and unpause per NB. */
|
||||
RigidbodyPauser?.Unpause();
|
||||
}
|
||||
|
||||
|
||||
private void PredictionManager_OnReplicateReplay(uint clientTick, uint serverTick)
|
||||
{
|
||||
uint replayTick = (IsOwner) ? clientTick : serverTick;
|
||||
for (int i = 0; i < _predictionBehaviours.Count; i++)
|
||||
_predictionBehaviours[i].Replicate_Replay_Start(replayTick);
|
||||
}
|
||||
|
||||
private void PredictionManager_OnPreReplicateReplay(uint clientTick, uint serverTick)
|
||||
{
|
||||
/* Adaptive smoother uses localTick (clientTick) to track graphical datas.
|
||||
* There's no need to use serverTick since the only purpose of adaptiveSmoother
|
||||
* is to smooth graphic changes, not update the transform itself. */
|
||||
if (!IsHost)
|
||||
_spectatorAdaptiveInterpolationSmoother?.OnPreReplicateReplay(clientTick, serverTick);
|
||||
}
|
||||
|
||||
private void PredictionManager_OnPostReplicateReplay(uint clientTick, uint serverTick)
|
||||
{
|
||||
/* Adaptive smoother uses localTick (clientTick) to track graphical datas.
|
||||
* There's no need to use serverTick since the only purpose of adaptiveSmoother
|
||||
* is to smooth graphic changes, not update the transform itself. */
|
||||
if (!IsHost)
|
||||
_spectatorAdaptiveInterpolationSmoother?.OnPostReplicateReplay(clientTick, serverTick);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if this object is colliding with any local client objects.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal bool CollidingWithLocalClient()
|
||||
{
|
||||
/* If it's been more than 1 tick since collision stayed
|
||||
* then do not consider as collided. */
|
||||
return (TimeManager.LocalTick - _collisionStayedTick) < 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when colliding with another object.
|
||||
/// </summary>
|
||||
private void OnCollisionEnter(Collision collision)
|
||||
{
|
||||
if (!ClientInitialized)
|
||||
return;
|
||||
if (_predictionType != PredictionType.Rigidbody)
|
||||
return;
|
||||
|
||||
GameObject go = collision.gameObject;
|
||||
if (CollisionEnteredLocalClientObject(go))
|
||||
CollisionEntered(go);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when collision has entered a local clients object.
|
||||
/// </summary>
|
||||
private void CollisionEntered(GameObject go)
|
||||
{
|
||||
_collisionStayedTick = TimeManager.LocalTick;
|
||||
_localClientCollidedObjects.Add(go);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when colliding with another object.
|
||||
/// </summary>
|
||||
private void OnCollisionEnter2D(Collision2D collision)
|
||||
{
|
||||
if (!ClientInitialized)
|
||||
return;
|
||||
if (_predictionType != PredictionType.Rigidbody2D)
|
||||
return;
|
||||
|
||||
GameObject go = collision.gameObject;
|
||||
if (CollisionEnteredLocalClientObject(go))
|
||||
CollisionEntered(go);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called when staying in collision with another object.
|
||||
/// </summary>
|
||||
private void OnCollisionStay(Collision collision)
|
||||
{
|
||||
if (!ClientInitialized)
|
||||
return;
|
||||
if (_predictionType != PredictionType.Rigidbody)
|
||||
return;
|
||||
|
||||
if (_localClientCollidedObjects.Contains(collision.gameObject))
|
||||
_collisionStayedTick = TimeManager.LocalTick;
|
||||
}
|
||||
/// <summary>
|
||||
/// Called when staying in collision with another object.
|
||||
/// </summary>
|
||||
private void OnCollisionStay2D(Collision2D collision)
|
||||
{
|
||||
if (!ClientInitialized)
|
||||
return;
|
||||
if (_predictionType != PredictionType.Rigidbody2D)
|
||||
return;
|
||||
|
||||
if (_localClientCollidedObjects.Contains(collision.gameObject))
|
||||
_collisionStayedTick = TimeManager.LocalTick;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a collision occurs and the smoothing type must perform operations.
|
||||
/// </summary>
|
||||
private bool CollisionEnteredLocalClientObject(GameObject go)
|
||||
{
|
||||
if (go.TryGetComponent<NetworkObject>(out NetworkObject nob))
|
||||
return nob.Owner.IsLocalClient;
|
||||
|
||||
//Fall through.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called when collision has exited a local clients object.
|
||||
/// </summary>
|
||||
private void TrySetCollisionExited()
|
||||
{
|
||||
/* If this object is no longer
|
||||
* colliding with local client objects
|
||||
* then unset collision.
|
||||
* This is done here instead of using
|
||||
* OnCollisionExit because often collisionexit
|
||||
* will be missed due to ignored ticks.
|
||||
* While not ignoring ticks is always an option
|
||||
* its not ideal because ignoring ticks helps
|
||||
* prevent over predicting. */
|
||||
TimeManager tm = TimeManager;
|
||||
if (tm == null || (_collisionStayedTick != 0 && (tm.LocalTick != _collisionStayedTick)))
|
||||
{
|
||||
_localClientCollidedObjects.Clear();
|
||||
_collisionStayedTick = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a NetworkBehaviour that uses prediction with the NetworkObject.
|
||||
/// This method should only be called once throughout the entire lifetime of this object.
|
||||
/// </summary>
|
||||
internal void RegisterPredictionBehaviourOnce(NetworkBehaviour nb)
|
||||
{
|
||||
_predictionBehaviours.Add(nb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets replicate tick and unordered replicate tick.
|
||||
/// </summary>
|
||||
internal void ResetReplicateTick()
|
||||
{
|
||||
ReplicateTick.Reset();
|
||||
LastUnorderedReplicateTick = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the last tick this NetworkBehaviour replicated with.
|
||||
/// </summary>
|
||||
internal void SetReplicateTick(uint value, bool setUnordered)
|
||||
{
|
||||
if (setUnordered)
|
||||
LastUnorderedReplicateTick = value;
|
||||
|
||||
ReplicateTick.Update(NetworkManager.TimeManager, value, EstimatedTick.OldTickOption.Discard);
|
||||
Owner.ReplicateTick.Update(NetworkManager.TimeManager, value, EstimatedTick.OldTickOption.Discard);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void Prediction_OnValidate()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
// InitializeSmoother(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_adaptiveSmoothingType == AdaptiveSmoothingType.Accuracy)
|
||||
_preconfiguredSmoothingDataPreview = _accurateSmoothingData;
|
||||
else if (_adaptiveSmoothingType == AdaptiveSmoothingType.Mixed)
|
||||
_preconfiguredSmoothingDataPreview = _mixedSmoothingData;
|
||||
else if (_adaptiveSmoothingType == AdaptiveSmoothingType.Gradual)
|
||||
_preconfiguredSmoothingDataPreview = _gradualSmoothingData;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user