diff --git a/MUNGA/MOVER.cpp b/MUNGA/MOVER.cpp index 4e0d8a1..5f260e6 100644 --- a/MUNGA/MOVER.cpp +++ b/MUNGA/MOVER.cpp @@ -32,16 +32,47 @@ static Scalar gLastPercent = 0.0f; // The second pair are a backstop on the answer, set deliberately wide so // that in every sane case the median decides it and these never bind. // +// Measured send rate on a live connection is about 30ms, so half a second +// is already sixteen times slower than anything healthy. +// static const Scalar kMinimumUpdateInterval = 0.001f; -static const Scalar kOutlierUpdateInterval = 2.0f; +static const Scalar kOutlierUpdateInterval = 0.5f; static const Scalar kMinimumPredictedInterval = 0.010f; -static const Scalar kMaximumPredictedInterval = 1.0f; + +// +// Never predict further ahead than this, which puts a floor under the +// dead reckoner's blend fraction: at a 20ms step the worst case becomes +// 0.02/(0.25+0.02), near enough 7% of the gap per step, so a pod still +// converges on its projection in a dozen steps instead of crawling. +// +static const Scalar kMaximumPredictedInterval = 0.25f; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // RP412NETPREDICT=0 restores the original single-sample prediction, so the // two can be compared on the same build and the same connection. // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Every path out of PredictUpdateInterval goes through here. It used not +// to, and the one that skipped it was the bug. +// +static Scalar + ClampPredictedInterval(Scalar interval) +{ + if (interval < kMinimumPredictedInterval) + { + return kMinimumPredictedInterval; + } + if (interval > kMaximumPredictedInterval) + { + return kMaximumPredictedInterval; + } + return interval; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// static Logical UseMedianPrediction() { @@ -918,12 +949,16 @@ Scalar } // - // Too few samples to hold an opinion. Fall back to the old behaviour - // rather than inventing a rate we have no evidence for. + // Too few samples to hold an opinion. Fall back to the gap we just saw + // rather than inventing a rate we have no evidence for - but clamp it + // like any other answer. Leaving this path unclamped let a 2.05s gap + // through in the first updates after an entity appeared, which drove + // the blend fraction to 0.0097 and stalled the step. That is every + // respawn, and it is exactly when the pod is being watched. // if (updateIntervalCount < 3) { - return latest; + return ClampPredictedInterval(latest); } // @@ -950,17 +985,7 @@ Scalar sorted[j + 1] = value; } - Scalar median = sorted[updateIntervalCount / 2]; - - if (median < kMinimumPredictedInterval) - { - median = kMinimumPredictedInterval; - } - if (median > kMaximumPredictedInterval) - { - median = kMaximumPredictedInterval; - } - return median; + return ClampPredictedInterval(sorted[updateIntervalCount / 2]); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~