mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
rmeove unused, disable logging
This commit is contained in:
parent
d5613321bf
commit
36295df476
@ -121,7 +121,7 @@ protected void BeginPredicting()
|
||||
// we know the time when our [Command] arrives on server: NetworkTime.predictedTime.
|
||||
predictionStartTime = NetworkTime.predictedTime; // !!! not .time !!!
|
||||
OnBeginPrediction();
|
||||
Debug.Log($"{name} BEGIN PREDICTING @ {predictionStartTime:F2}");
|
||||
// Debug.Log($"{name} BEGIN PREDICTING @ {predictionStartTime:F2}");
|
||||
}
|
||||
|
||||
double blendingStartTime;
|
||||
@ -132,7 +132,7 @@ protected void BeginBlending()
|
||||
// if (debugColors) rend.material.color = blendingAheadColor; set in update depending on ahead/behind
|
||||
blendingStartTime = NetworkTime.time;
|
||||
OnBeginBlending();
|
||||
Debug.Log($"{name} BEGIN BLENDING");
|
||||
// Debug.Log($"{name} BEGIN BLENDING");
|
||||
}
|
||||
|
||||
protected void BeginFollowing()
|
||||
@ -141,7 +141,7 @@ protected void BeginFollowing()
|
||||
state = ForecastState.FOLLOWING;
|
||||
if (debugColors) rend.material.color = originalColor;
|
||||
OnBeginFollow();
|
||||
Debug.Log($"{name} BEGIN FOLLOW");
|
||||
// Debug.Log($"{name} BEGIN FOLLOW");
|
||||
}
|
||||
|
||||
void UpdateServer()
|
||||
@ -177,17 +177,6 @@ protected virtual bool IsMoving() =>
|
||||
predictedRigidbody.velocity.sqrMagnitude >= velocitySensitivitySqr ||
|
||||
predictedRigidbody.angularVelocity.sqrMagnitude >= angularVelocitySensitivitySqr;
|
||||
|
||||
// check if following the remote state would move us backwards, or forward.
|
||||
// we never want to interpolate backwards.
|
||||
bool RemoteInSameDirection()
|
||||
{
|
||||
Vector3 direction = lastReceivedState.position - transform.position;
|
||||
|
||||
// is this in the direction we are going, or behind us (the opposite)?
|
||||
bool opposite = Vector3.Dot(direction, predictedRigidbody.velocity) < 0;
|
||||
return !opposite;
|
||||
}
|
||||
|
||||
// when using Fast mode, we don't create any ghosts.
|
||||
// but we still want to check IsMoving() in order to support the same
|
||||
// user callbacks.
|
||||
@ -204,7 +193,7 @@ void UpdateClient()
|
||||
// but technically doesn't make a difference if it just barely moved anyway.
|
||||
if (lastReceivedState.timestamp > predictionStartTime)
|
||||
{
|
||||
Debug.Log($"{name} END PREDICTING because received state = {lastReceivedState.timestamp:F2} > prediction start = {predictionStartTime:F2}");
|
||||
// Debug.Log($"{name} END PREDICTING because received state = {lastReceivedState.timestamp:F2} > prediction start = {predictionStartTime:F2}");
|
||||
BeginBlending();
|
||||
}
|
||||
}
|
||||
@ -249,7 +238,7 @@ void FixedUpdateClient()
|
||||
float blendingElapsed = BlendingElapsedTime();
|
||||
float relativeElapsed = blendingElapsed / blendingTime;
|
||||
float p = blendingCurve.Evaluate(relativeElapsed);
|
||||
Debug.Log($"{name} BLENDING @ {blendingElapsed:F2} / {blendingTime:F2} => {(p*100):F0}%");
|
||||
// Debug.Log($"{name} BLENDING @ {blendingElapsed:F2} / {blendingTime:F2} => {(p*100):F0}%");
|
||||
|
||||
// blend local position to remote position
|
||||
Vector3 currentPosition = predictedRigidbody.position;
|
||||
@ -276,7 +265,7 @@ void FixedUpdateClient()
|
||||
// transition to FOLLOWING once p = 100%
|
||||
if (p >= 1)
|
||||
{
|
||||
Debug.Log($"{name} END BLENDING");
|
||||
// Debug.Log($"{name} END BLENDING");
|
||||
BeginFollowing();
|
||||
}
|
||||
}
|
||||
@ -313,7 +302,7 @@ void OnCollisionEnter(Collision collision)
|
||||
|
||||
// is the other object a ForecastRigidbody?
|
||||
if (!collision.collider.TryGetComponent(out ForecastRigidbody other)) return;
|
||||
Debug.Log($"{name} @ {state} collided with {other.name} @ {other.state}");
|
||||
// Debug.Log($"{name} @ {state} collided with {other.name} @ {other.state}");
|
||||
|
||||
// is the other object already predicting? then don't call events again.
|
||||
if (other.state != ForecastState.FOLLOWING) return;
|
||||
@ -335,72 +324,6 @@ protected virtual void OnBeginPrediction() {}
|
||||
protected virtual void OnBeginBlending() {}
|
||||
protected virtual void OnBeginFollow() {}
|
||||
|
||||
void ApplyState(double timestamp, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)
|
||||
{
|
||||
/*
|
||||
// fix rigidbodies seemingly dancing in place instead of coming to rest.
|
||||
// hard snap to the position below a threshold velocity.
|
||||
// this is fine because the visual object still smoothly interpolates to it.
|
||||
// => consider both velocity and angular velocity (in case of Rigidbodies only rotating with joints etc.)
|
||||
if (predictedRigidbody.velocity.magnitude <= snapThreshold &&
|
||||
predictedRigidbody.angularVelocity.magnitude <= snapThreshold)
|
||||
{
|
||||
// Debug.Log($"Prediction: snapped {name} into place because velocity {predictedRigidbody.velocity.magnitude:F3} <= {snapThreshold:F3}");
|
||||
|
||||
// apply server state immediately.
|
||||
// important to apply velocity as well, instead of Vector3.zero.
|
||||
// in case an object is still slightly moving, we don't want it
|
||||
// to stop and start moving again on client - slide as well here.
|
||||
predictedRigidbody.position = position;
|
||||
predictedRigidbody.rotation = rotation;
|
||||
// projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error
|
||||
if (!predictedRigidbody.isKinematic)
|
||||
{
|
||||
predictedRigidbody.velocity = velocity;
|
||||
predictedRigidbody.angularVelocity = angularVelocity;
|
||||
}
|
||||
|
||||
// clear history and insert the exact state we just applied.
|
||||
// this makes future corrections more accurate.
|
||||
stateHistory.Clear();
|
||||
stateHistory.Add(timestamp, new RigidbodyState(
|
||||
timestamp,
|
||||
Vector3.zero,
|
||||
position,
|
||||
Quaternion.identity,
|
||||
rotation,
|
||||
Vector3.zero,
|
||||
velocity,
|
||||
Vector3.zero,
|
||||
angularVelocity
|
||||
));
|
||||
|
||||
// user callback
|
||||
OnSnappedIntoPlace();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// we have a callback for snapping into place (above).
|
||||
// we also need one for corrections without snapping into place.
|
||||
// call it before applying pos/rot/vel in case we need to set kinematic etc.
|
||||
OnBeforeApplyState();
|
||||
|
||||
// apply the state to the Rigidbody
|
||||
// Fast mode doesn't separate physics from rendering.
|
||||
// The only smoothing we get is from Rigidbody.MovePosition.
|
||||
predictedRigidbody.MovePosition(position);
|
||||
predictedRigidbody.MoveRotation(rotation);
|
||||
|
||||
// there's only one way to set velocity.
|
||||
// (projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error)
|
||||
if (!predictedRigidbody.isKinematic)
|
||||
{
|
||||
predictedRigidbody.velocity = velocity;
|
||||
predictedRigidbody.angularVelocity = angularVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
// process a received server state.
|
||||
// compares it against our history and applies corrections if needed.
|
||||
RigidbodyState lastReceivedState;
|
||||
@ -408,155 +331,6 @@ void OnReceivedState(double timestamp, RigidbodyState data)//, bool sleeping)
|
||||
{
|
||||
// store last time
|
||||
lastReceivedState = data;
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// performance: get Rigidbody position & rotation only once,
|
||||
// and together via its transform
|
||||
predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation);
|
||||
|
||||
// OPTIONAL performance optimization when comparing idle objects.
|
||||
// even idle objects will have a history of ~32 entries.
|
||||
// sampling & traversing through them is unnecessarily costly.
|
||||
// instead, compare directly against the current rigidbody position!
|
||||
// => this is technically not 100% correct if an object runs in
|
||||
// circles where it may revisit the same position twice.
|
||||
// => but practically, objects that didn't move will have their
|
||||
// whole history look like the last inserted state.
|
||||
// => comparing against that is free and gives us a significant
|
||||
// performance saving vs. a tiny chance of incorrect results due
|
||||
// to objects running in circles.
|
||||
// => the RecordState() call below is expensive too, so we want to
|
||||
// do this before even recording the latest state. the only way
|
||||
// to do this (in case last recorded state is too old), is to
|
||||
// compare against live rigidbody.position without any recording.
|
||||
// this is as fast as it gets for skipping idle objects.
|
||||
//
|
||||
// if this ever causes issues, feel free to disable it.
|
||||
float positionToStateDistanceSqr = Vector3.SqrMagnitude(state.position - physicsPosition);
|
||||
if (compareLastFirst &&
|
||||
// Vector3.Distance(state.position, physicsPosition) < positionCorrectionThreshold && // slow comparison
|
||||
positionToStateDistanceSqr < positionCorrectionThresholdSqr && // fast comparison
|
||||
Quaternion.Angle(state.rotation, physicsRotation) < rotationCorrectionThreshold)
|
||||
{
|
||||
// Debug.Log($"OnReceivedState for {name}: taking optimized early return!");
|
||||
return;
|
||||
}
|
||||
|
||||
// we only capture state every 'interval' milliseconds.
|
||||
// so the newest entry in 'history' may be up to 'interval' behind 'now'.
|
||||
// if there's no latency, we may receive a server state for 'now'.
|
||||
// sampling would fail, if we haven't recorded anything in a while.
|
||||
// to solve this, always record the current state when receiving a server state.
|
||||
RecordState();
|
||||
|
||||
// correction requires at least 2 existing states for 'before' and 'after'.
|
||||
// if we don't have two yet, drop this state and try again next time once we recorded more.
|
||||
if (stateHistory.Count < 2) return;
|
||||
|
||||
RigidbodyState oldest = stateHistory.Values[0];
|
||||
RigidbodyState newest = stateHistory.Values[stateHistory.Count - 1];
|
||||
|
||||
// edge case: is the state older than the oldest state in history?
|
||||
// this can happen if the client gets so far behind the server
|
||||
// that it doesn't have a recored history to sample from.
|
||||
// in that case, we should hard correct the client.
|
||||
// otherwise it could be out of sync as long as it's too far behind.
|
||||
if (state.timestamp < oldest.timestamp)
|
||||
{
|
||||
// when starting, client may only have 2-3 states in history.
|
||||
// it's expected that server states would be behind those 2-3.
|
||||
// only show a warning if it's behind the full history limit!
|
||||
if (stateHistory.Count >= stateHistoryLimit)
|
||||
Debug.LogWarning($"Hard correcting client object {name} because the client is too far behind the server. History of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This would cause the client to be out of sync as long as it's behind.");
|
||||
|
||||
// force apply the state
|
||||
ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity);
|
||||
return;
|
||||
}
|
||||
|
||||
// edge case: is it newer than the newest state in history?
|
||||
// this can happen if client's predictedTime predicts too far ahead of the server.
|
||||
// in that case, log a warning for now but still apply the correction.
|
||||
// otherwise it could be out of sync as long as it's too far ahead.
|
||||
//
|
||||
// for example, when running prediction on the same machine with near zero latency.
|
||||
// when applying corrections here, this looks just fine on the local machine.
|
||||
if (newest.timestamp < state.timestamp)
|
||||
{
|
||||
// the correction is for a state in the future.
|
||||
// we clamp it to 'now'.
|
||||
// but only correct if off by threshold.
|
||||
// TODO maybe we should interpolate this back to 'now'?
|
||||
// if (Vector3.Distance(state.position, physicsPosition) >= positionCorrectionThreshold) // slow comparison
|
||||
if (positionToStateDistanceSqr >= positionCorrectionThresholdSqr) // fast comparison
|
||||
{
|
||||
// this can happen a lot when latency is ~0. logging all the time allocates too much and is too slow.
|
||||
// double ahead = state.timestamp - newest.timestamp;
|
||||
// Debug.Log($"Hard correction because the client is ahead of the server by {(ahead*1000):F1}ms. History of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This can happen when latency is near zero, and is fine unless it shows jitter.");
|
||||
ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// find the two closest client states between timestamp
|
||||
if (!Prediction.Sample(stateHistory, timestamp, out RigidbodyState before, out RigidbodyState after, out int afterIndex, out double t))
|
||||
{
|
||||
// something went very wrong. sampling should've worked.
|
||||
// hard correct to recover the error.
|
||||
Debug.LogError($"Failed to sample history of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This should never happen because the timestamp is within history.");
|
||||
ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity);
|
||||
return;
|
||||
}
|
||||
|
||||
// interpolate between them to get the best approximation
|
||||
RigidbodyState interpolated = RigidbodyState.Interpolate(before, after, (float)t);
|
||||
|
||||
// calculate the difference between where we were and where we should be
|
||||
// TODO only position for now. consider rotation etc. too later
|
||||
// float positionToInterpolatedDistance = Vector3.Distance(state.position, interpolated.position); // slow comparison
|
||||
float positionToInterpolatedDistanceSqr = Vector3.SqrMagnitude(state.position - interpolated.position); // fast comparison
|
||||
float rotationToInterpolatedDistance = Quaternion.Angle(state.rotation, interpolated.rotation);
|
||||
// Debug.Log($"Sampled history of size={stateHistory.Count} @ {timestamp:F3}: client={interpolated.position} server={state.position} difference={difference:F3} / {correctionThreshold:F3}");
|
||||
|
||||
// too far off? then correct it
|
||||
if (positionToInterpolatedDistanceSqr >= positionCorrectionThresholdSqr || // fast comparison
|
||||
//positionToInterpolatedDistance >= positionCorrectionThreshold || // slow comparison
|
||||
rotationToInterpolatedDistance >= rotationCorrectionThreshold)
|
||||
{
|
||||
// Debug.Log($"CORRECTION NEEDED FOR {name} @ {timestamp:F3}: client={interpolated.position} server={state.position} difference={difference:F3}");
|
||||
|
||||
// show the received correction position + velocity for debugging.
|
||||
// helps to compare with the interpolated/applied correction locally.
|
||||
//Debug.DrawLine(state.position, state.position + state.velocity * 0.1f, Color.white, lineTime);
|
||||
|
||||
// insert the correction and correct the history on top of it.
|
||||
// returns the final recomputed state after rewinding.
|
||||
RigidbodyState recomputed = Prediction.CorrectHistory(stateHistory, stateHistoryLimit, state, before, after, afterIndex);
|
||||
|
||||
// blend the final correction towards current server state over time.
|
||||
// this is the idea of ForecastRigidbody.
|
||||
// TODO once we are at server state, let snapshot interpolation take over.
|
||||
// RigidbodyState blended = RigidbodyState.Interpolate(recomputed, state, blendPerSync);
|
||||
// Debug.DrawLine(recomputed.position, blended.position, Color.green, 10.0f);
|
||||
|
||||
// log, draw & apply the final position.
|
||||
// always do this here, not when iterating above, in case we aren't iterating.
|
||||
// for example, on same machine with near zero latency.
|
||||
// int correctedAmount = stateHistory.Count - afterIndex;
|
||||
// Debug.Log($"Correcting {name}: {correctedAmount} / {stateHistory.Count} states to final position from: {rb.position} to: {last.position}");
|
||||
//Debug.DrawLine(physicsCopyRigidbody.position, recomputed.position, Color.green, lineTime);
|
||||
ApplyState(recomputed.timestamp, recomputed.position, recomputed.rotation, recomputed.velocity, recomputed.angularVelocity);
|
||||
|
||||
// insert the blended state into the history.
|
||||
// this makes it permanent, instead of blending every time but rarely recording.
|
||||
RecordState();
|
||||
|
||||
// user callback
|
||||
OnCorrected();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// send state to clients every sendInterval.
|
||||
|
Loading…
Reference in New Issue
Block a user