Firstly PCF did not write interpolation properly, on mouse, on animations, or anything. What they typically did was:
rotation = m_lastRotation + rotationDelta*0.33
where rotationDelta = m_lastRotation – m_nextRotation
Whereas what they should have is:
rotation = m_lastRotation + rotationDeltaRate*deltatime
where rotationDeltaRate = (m_lastRotation – m_nextRotation) / deltatimeperiod
They have made this mistake lots. Fixing interpolation in the bits we can see is straightforward. As I discussed with PeTjA, we can apply this interpolation to ALL items on the map, so that everything moves smoothly.
Typically linear interpolation is used for unpredictable items, and Catmull-Rom (cubic) splines for predictable movement (e.g. any mass subjected to constant or continuous accelerations.)
Yikes! This is an important one. Ever since I improved item spawn times for PK++, I have always been suspicious of how accurate PKs timing is. We all know it has the ability to run too fast/slow at times. To test this I relied on the LUA os.clock() and os.time(). os.time() gives tick time (since 1982 or so) in seconds, whereas os.clock() gives seconds fractions since the code begins. It should be noted that math.floor(os.time()-os.clock()) is constant and remains constant.
The first problem is that PK works out time by adding deltas. This is CRAZY, since floating point (even double) will exhibit rounding errors quite quickly through any addition.
To test this, I set up the delta addition in comparison to os.time and os.clock. They were WAY off. Particularly because my machine is slow and does not always achieve the 45 FPS of the server. When the machine is slow it ASSUMES that the delta is 1.0/FPS regardless of whether it achieves that or not.
It gets worse though…
The MEASURED delta used varies by a huge amount, but dependent on it trying to hit a certain FPS. This is because they have imposed a minimum loop period of 30FPS or 0.0167secs. What this means is that loops can only occur in multiples of 30FPS, but such that over a second or so, they will meet the total FPS.
Say for example the desired FPS is 45. For PK this will run like this:
Of course the average delta for 45FPS is correct.
In other words the loops are not evenly spaced in time. What is terrible for netcode and interpolation and ANYTHING else.
This explains why 30 and 60 FPS seem to be smoothest. Iterations seem to only occur in 0-30, 30 or 62.5 FPS steps.
It is possible to stall the frames so they become evenly spaced (by setting FPS very very high and limiting within the LUA). But the issue is not that a frame goes too quickly, but too slowly, to average.
The maximum speed at which Havok can run is also set, at 62.5 FPS (or rather, this is the minimum time step it can accept).
Finally we can address these issues by setting the frame rate to zero (so max speed), then controlling the actual tickrate through the LUA. A suitable tickrate is 62.5 FPS providing one tick per physics iteration. This has already been tested for CPU usage and is very low.
Given this, the number of updates a client can recieve (q3s snaps) MUST be limited on the client. After testing, somewhere between 10 and 20 gives reasonable looking gameplay. As a current rule of thumb, the data is :
= number of players * update rate (serverframerate on client) * 30
So 32 players at 10fps is around 9KBps which is reasonable.
Additional work needs to be completed before reducing the update data further. This should be possible without access to the source code.