In 26.3, there was a new type of interpolation introduced which is now used for most living entities. I’m not mainly gonna talk about what this new Interpolation actually does, but rather about what small bugs cause there to be such observable stuttering.
This is mainly caused by the fact that an interpolation on the client takes less time than it takes for new information to arrive to the server, which is now very common.
Previously a server sent a packet every 2 ticks for most entities and the client interpolated them over the span of 3, leaving a tick to spare. Now the client also uses the EntityType.updateInterval() field to determine how long each interpolation should last, making it increasingly common for the client to stop interpolating before new information arrives.
Additionally, the new packet protocol allows servers to send full paths including the tick duration for each segment to clients in move entity packets. It seems that vanilla servers send paths with very small tick durations (1-2) when an entity is just starting to move, which causes there to be an obvious jitter of up to 2 ticks standing still when a player hits an entity not currently in motion.
Also I believe the core logic of the new interpolation method to be somewhat flawed and I believe it should be more rigorously tested as it’s quite complicated. There are two methods doing most of the important work, getNewPositionAndRotation() and
advance(). We can think of advance() as defining the speed at which we are interpolating and getNewPositionAndRotation() as setting the new value. Instead of the interpolation being initiated with currentStepTicks = 1.0F, it should be done with currentStepTicks = 0.0F and advance() should be called before getNewPositionAndRotation().
Another problem arises due to both of the above methods checking if the end of the interpolation has been reached. Concretely advance() checks if the interpolation speed for the next movement is >= the amount that is left. If it is it caps currentStepTicks so that it doesnt exceed the end. However, getNewPositionAndRotation() then loops over the active steps and removes any that it surpasses. The bound of currentStepTicks from advance() can now cause the last step not to be removed, causing the game to think that there is an active interpolation constantly, due to the following:
public boolean hasActiveInterpolation() {
return !this.interpolationData.remainingSteps.isEmpty();
}
When the end of all current steps is reached it also doesn’t seem like the interpolation is properly reset for the next interpolation to start. I believe setStartingPoint() should probably also reset remainingTicks and the reset() method might want to include currentStepTicks.
I will look into this further and might attach more code to show exactly where the problems lie and how they can be fixed.
Linked issues
Attachments
Comments 2
Thank you for your report!
We're tracking this issue in MC-311974, so this ticket is being resolved and linked as a duplicate.
If you would like to add a vote and any extra information to the main ticket it would be appreciated.
If you haven't already, you might like to make use of the search feature to see if the issue has already been mentioned.
Quick Links:
📓 Bug Tracker Guidelines – 💬 Community Support – 📧 Mojang Support (Technical Issues) – 📧 Microsoft Support (Account Issues)
📓 Project Summary – ✍️ Feedback and Suggestions – 📖 Game Wiki
Thank you for helping us improve Minecraft! We saved your files: