mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 19:10:32 +00:00
PredictedRigidbody: sync & show remote.sleeping to easier debug objects coming to rest
This commit is contained in:
parent
824712df9c
commit
867bf7c492
@ -19,6 +19,7 @@ namespace Mirror
|
|||||||
public class PredictedRigidbody : NetworkBehaviour
|
public class PredictedRigidbody : NetworkBehaviour
|
||||||
{
|
{
|
||||||
Transform tf; // this component is performance critical. cache .transform getter!
|
Transform tf; // this component is performance critical. cache .transform getter!
|
||||||
|
Renderer rend;
|
||||||
|
|
||||||
// Prediction sometimes moves the Rigidbody to a ghost object.
|
// Prediction sometimes moves the Rigidbody to a ghost object.
|
||||||
// .predictedRigidbody is always kept up to date to wherever the RB is.
|
// .predictedRigidbody is always kept up to date to wherever the RB is.
|
||||||
@ -93,7 +94,8 @@ public class PredictedRigidbody : NetworkBehaviour
|
|||||||
public bool reduceSendsWhileIdle = true;
|
public bool reduceSendsWhileIdle = true;
|
||||||
|
|
||||||
[Header("Debugging")]
|
[Header("Debugging")]
|
||||||
public float lineTime = 10;
|
[Tooltip("Useful to debug objects not coming to rest. This color codes the local objects which are already asleep on the server.")]
|
||||||
|
public bool showRemoteSleeping = false;
|
||||||
|
|
||||||
// Rigidbody & Collider are moved out into a separate object.
|
// Rigidbody & Collider are moved out into a separate object.
|
||||||
// this way the visual object can smoothly follow.
|
// this way the visual object can smoothly follow.
|
||||||
@ -112,9 +114,12 @@ public class PredictedRigidbody : NetworkBehaviour
|
|||||||
Quaternion initialRotation;
|
Quaternion initialRotation;
|
||||||
// Vector3 initialScale; // don't change scale for now. causes issues with parenting.
|
// Vector3 initialScale; // don't change scale for now. causes issues with parenting.
|
||||||
|
|
||||||
|
Color originalColor;
|
||||||
|
|
||||||
protected virtual void Awake()
|
protected virtual void Awake()
|
||||||
{
|
{
|
||||||
tf = transform;
|
tf = transform;
|
||||||
|
rend = GetComponent<Renderer>();
|
||||||
predictedRigidbody = GetComponent<Rigidbody>();
|
predictedRigidbody = GetComponent<Rigidbody>();
|
||||||
if (predictedRigidbody == null) throw new InvalidOperationException($"Prediction: {name} is missing a Rigidbody component.");
|
if (predictedRigidbody == null) throw new InvalidOperationException($"Prediction: {name} is missing a Rigidbody component.");
|
||||||
predictedRigidbodyTransform = predictedRigidbody.transform;
|
predictedRigidbodyTransform = predictedRigidbody.transform;
|
||||||
@ -133,6 +138,9 @@ protected virtual void Awake()
|
|||||||
motionSmoothingVelocityThresholdSqr = motionSmoothingVelocityThreshold * motionSmoothingVelocityThreshold;
|
motionSmoothingVelocityThresholdSqr = motionSmoothingVelocityThreshold * motionSmoothingVelocityThreshold;
|
||||||
motionSmoothingAngularVelocityThresholdSqr = motionSmoothingAngularVelocityThreshold * motionSmoothingAngularVelocityThreshold;
|
motionSmoothingAngularVelocityThresholdSqr = motionSmoothingAngularVelocityThreshold * motionSmoothingAngularVelocityThreshold;
|
||||||
positionCorrectionThresholdSqr = positionCorrectionThreshold * positionCorrectionThreshold;
|
positionCorrectionThresholdSqr = positionCorrectionThreshold * positionCorrectionThreshold;
|
||||||
|
|
||||||
|
// renderer
|
||||||
|
originalColor = rend.material.color;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void CopyRenderersAsGhost(GameObject destination, Material material)
|
protected virtual void CopyRenderersAsGhost(GameObject destination, Material material)
|
||||||
@ -662,7 +670,7 @@ void ApplyState(double timestamp, Vector3 position, Quaternion rotation, Vector3
|
|||||||
|
|
||||||
// process a received server state.
|
// process a received server state.
|
||||||
// compares it against our history and applies corrections if needed.
|
// compares it against our history and applies corrections if needed.
|
||||||
void OnReceivedState(double timestamp, RigidbodyState state)
|
void OnReceivedState(double timestamp, RigidbodyState state, bool sleeping)
|
||||||
{
|
{
|
||||||
// always update remote state ghost
|
// always update remote state ghost
|
||||||
if (remoteCopy != null)
|
if (remoteCopy != null)
|
||||||
@ -672,6 +680,12 @@ void OnReceivedState(double timestamp, RigidbodyState state)
|
|||||||
remoteCopyTransform.localScale = tf.lossyScale; // world scale! see CreateGhosts comment.
|
remoteCopyTransform.localScale = tf.lossyScale; // world scale! see CreateGhosts comment.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// color code remote sleeping objects to debug objects coming to rest
|
||||||
|
if (showRemoteSleeping)
|
||||||
|
{
|
||||||
|
rend.material.color = sleeping ? Color.gray : originalColor;
|
||||||
|
}
|
||||||
|
|
||||||
// performance: get Rigidbody position & rotation only once,
|
// performance: get Rigidbody position & rotation only once,
|
||||||
// and together via its transform
|
// and together via its transform
|
||||||
predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation);
|
predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation);
|
||||||
@ -830,7 +844,13 @@ public override void OnSerialize(NetworkWriter writer, bool initialState)
|
|||||||
// writer.WriteVector3(predictedRigidbody.angularVelocity);
|
// writer.WriteVector3(predictedRigidbody.angularVelocity);
|
||||||
|
|
||||||
// performance optimization: write a whole struct at once via blittable:
|
// performance optimization: write a whole struct at once via blittable:
|
||||||
PredictedSyncData data = new PredictedSyncData(Time.deltaTime, position, rotation, predictedRigidbody.velocity, predictedRigidbody.angularVelocity);
|
PredictedSyncData data = new PredictedSyncData(
|
||||||
|
Time.deltaTime,
|
||||||
|
position,
|
||||||
|
rotation,
|
||||||
|
predictedRigidbody.velocity,
|
||||||
|
predictedRigidbody.angularVelocity,
|
||||||
|
predictedRigidbody.IsSleeping());
|
||||||
writer.WritePredictedSyncData(data);
|
writer.WritePredictedSyncData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -855,6 +875,7 @@ public override void OnDeserialize(NetworkReader reader, bool initialState)
|
|||||||
Quaternion rotation = data.rotation;
|
Quaternion rotation = data.rotation;
|
||||||
Vector3 velocity = data.velocity;
|
Vector3 velocity = data.velocity;
|
||||||
Vector3 angularVelocity = data.angularVelocity;
|
Vector3 angularVelocity = data.angularVelocity;
|
||||||
|
bool sleeping = data.sleeping != 0;
|
||||||
|
|
||||||
// server sends state at the end of the frame.
|
// server sends state at the end of the frame.
|
||||||
// parse and apply the server's delta time to our timestamp.
|
// parse and apply the server's delta time to our timestamp.
|
||||||
@ -868,7 +889,7 @@ public override void OnDeserialize(NetworkReader reader, bool initialState)
|
|||||||
if (oneFrameAhead) timestamp += serverDeltaTime;
|
if (oneFrameAhead) timestamp += serverDeltaTime;
|
||||||
|
|
||||||
// process received state
|
// process received state
|
||||||
OnReceivedState(timestamp, new RigidbodyState(timestamp, Vector3.zero, position, Quaternion.identity, rotation, Vector3.zero, velocity, Vector3.zero, angularVelocity));
|
OnReceivedState(timestamp, new RigidbodyState(timestamp, Vector3.zero, position, Quaternion.identity, rotation, Vector3.zero, velocity, Vector3.zero, angularVelocity), sleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnValidate()
|
protected override void OnValidate()
|
||||||
|
@ -22,15 +22,17 @@ public struct PredictedSyncData
|
|||||||
public Quaternion rotation; // 16 bytes (word aligned)
|
public Quaternion rotation; // 16 bytes (word aligned)
|
||||||
public Vector3 velocity; // 12 bytes (word aligned)
|
public Vector3 velocity; // 12 bytes (word aligned)
|
||||||
public Vector3 angularVelocity; // 12 bytes (word aligned)
|
public Vector3 angularVelocity; // 12 bytes (word aligned)
|
||||||
|
public byte sleeping; // 1 byte: bool isn't blittable
|
||||||
|
|
||||||
// constructor for convenience
|
// constructor for convenience
|
||||||
public PredictedSyncData(float deltaTime, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)
|
public PredictedSyncData(float deltaTime, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity, bool sleeping)
|
||||||
{
|
{
|
||||||
this.deltaTime = deltaTime;
|
this.deltaTime = deltaTime;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
this.velocity = velocity;
|
this.velocity = velocity;
|
||||||
this.angularVelocity = angularVelocity;
|
this.angularVelocity = angularVelocity;
|
||||||
|
this.sleeping = sleeping ? (byte)1 : (byte)0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user