Last server records
Pro Nub

Calculating distance

Posted by Kpoluk 13 May 2023 in 12:13
As we already know, player's model interacts with a map as a box, i.e. parallelepiped with a square base. Side of the square is 32 units, and the box's height is 72 units in standing state and 36 units when sitting. In order to jump over 240 block the center of the box needs to move 208 units horizontally, while the rest 32 units are provided by the width of model box:


It's all true unless we deal with blocks that have edges aligned to the main axes of a map. But what if we place 240 block at the angle of 45°? In this case movement of our box in top view will look like this:


The thing is that when we stand and turn in the game, our box doesn't move actually. Game developers call this AABB - axis-aligned bounding box. From its name you can guess that box axes are always aligned to the base axes of a map. Let's calculate a minimal distance that the center of the box required to pass in order to jump over turned 240 block:

240 - sqrt(2) * 32 = 194.745

To understand how difficult this jump is we just need to add 32 units, and then we'll get 226.745, i.e. 240 block is easier than 227. Back in the days this feature was call Flibo Bug by the name of Flibo who pointed it out. On our servers and in KZ-Rush LAN server we have a plugin allowing to measure distance between two points and also gauge the difficulty of a jump with help of a parameter called Estimated LJ, more info about this can be found in a special article.

The next thing to recall is a teleport from the article about EdgeBug and JumpBug physics, performed by the function PM_CategorizePosition. When there are less than 2 units between the box and the land, engine teleports box to the ground. This teleports works more often than you could imagine. When we jump on a flat surface, the teleport happens at the end of lj with duck, lj with no duck, after double duck and even after some bhops (it depends on the height of jump, i.e. on FOG and fuser2). That's why in all of these cases the duration of the jump is measured as an integer number of frames. However if the jump is done on the block, the teleport may not happen. In the article about LongJump physics we've learned that a regular lj is 73 frames long, but DeathClaw spent also a part of 74th frame in the air. The reason is that at the end of 73rd frame DeathClaw was still above the gap between blocks, so there were more than 2 units between his box and the ground:


At the end of 73rd frame the lower edge of the box is at the point A, and if there wasn't any block, one frame later it would be at the point B. However thanks to the function PM_FlyMove the engine finds point C where box collides with a block and changes the direction of movement, ending up at the point D.

Let put ourself in the place of demochecker or his program and imagine that we need to calculate the distance of longjump by the given demo. We parse the demo and extract the duration dt of 74th frame, velocity (Vx_A, Vy_A, Vz_A) at the point A, so now we can receive coordinates (x_B, y_B, z_B) of the point B:

x_B = x_A + Vx_A * dt
y_B = y_A + Vy_A * dt
z_B = z_A + Vz_A * dt

The height of the point C is the same as for point D, so the next step is calculating of a fraction = AC / AB and coordinates of C:

fraction = (z_A - z_D) / (z_A - z_B)
x_C = x_A + (x_B - x_A) * fraction
y_C = y_A + (y_B - y_A) * fraction
z_C = z_A + (z_B - z_A) * fraction

That's it, now we just have to calculate distance from the point S where jump started to the point C:

distance = sqrt((x_C - x_S) * (x_C - x_S) + (y_C - y_S) * (y_C - y_S))

Now consider the same task for our plugin of LJ statistics. The first thing to do is to repeat the trace of the engine 2 units down from the last position in the air. If trace hits the ground than teleport has been performed and we can use x_A and y_A as coordinates of the end point. And if trace doesn't touch the ground plugin does the same calculations as we did before. The only difference is that plugin deals with any kind of surfaces, so in general we cannot use the height of point D. That is why in order to get the value of fraction plugin performs a trace from A to B.

But this is not the only complexity plugin faces. Let's take any bhop-lj block from kz_longjumps3. If server doesn't have mpbhop turned on, then after touching the bhop block player begins to descend with it until the moment of jump. The more bhop FOG, the lower player will be at the start of the flight. That is why playing on maps without mpbhop is harder, at that the higher speed of block the more difficulties player meets. Because of this lowering, the vertical coordinate of the player at the moment of the jump is lower than at the end of the flight. For the jump to be counted as successful plugin remembers the position of player at the end of the last frame before touching of the block. At this moment engine has already placed the player on the block, but the blocks hasn't started to go down yet.

In fact there are a lot more complexities, cause you need to know which frame to use as a data source, how to manage failed jumps and distinguish jump with and duck and without it. But we've already grasped the essence of the calculations, so we will leave the details for the developers.