Weekly Update #76

I’ll use “localGameTime” for what is called “renderTime” in my code and “displayTime” in flaviens.

Normally you or the server doesn’t control other ships. So this situation isn’t realistic.
If another player controls his ship he sends that change to the server. The server then incorporates that change into following snapshots and sends them to you. After that you’ll be able to see the course correction.

The only way for everyone to hit “the gas” at the same time is when something happens ingame at a fixed time.
This isn’t different from other games. If you have ever tried coordinating in them.

That’s not what’s happening. Time itself slows down. This allows you to stay in formation with everything else when you lag out. In “Lomsor_15” I have added a display that shows the current speed of the localGameTime. 1 s/s is normal. As we all know.


First off let me say that I understand what you point to. Usually a game has a fixed cycle times for such things one can rely on. By slowing down time these cycles might run more often than they should in a certain localGameTime-frame.

But just bear with me please …

Justification
By letting the physics continue while you change localGameTime you break that exact relationship. If it is not slowed down the client and server desync.
The client is playing in the past. If lag increases he needs to play further in the past. So you change your localGameTime.

  • If you change it instantly everything is fine. All the remote ships are jumped back to older positions but your ship stays where it was. You now play further in the past.

  • If you change it over multiple cycles but let the local physics run, like you did in the original Interpolation test. The remote ships will be set back over a period of time. But you will have travelled forward in the meantime.
    All other ships now are further in the past except for the players ship time, it didn’t change.
    You have effectively run more physics cycles. If you compare their localGameTime timespamps they will be spaced at different intervals.

There you have a different outcome.

I don’t see why the distance to the other ship should change when my latency changes. And so won’t the server. The server will set the player back to where he should be. Without the player doing anything wrong.

  • If you change the speed of localGameTime clock like I suggest as option 2 further down, physics still runs in a fixed step relative to the localGameTime clock!
    For instance. 100 physics ticks per localGame Second. If you slow down or speed up the rate at which localGameTime change (speed of time) these ticks will still be spaced exactly the same if you compare their localGameTime timespamp.
    Interpolating time is effectively making the timesmooth have the same effect as an instant change of localGameTime

Solution

  1. Make localGameTime changes instant
    Screw all this interpolation stuff. Take my “setTargetTime” code.
    Do this:renderTime = targetTime;
    Set latencySampleAmmount high.
    Usual lag and jitter should run quite stable. Some “snaps” when first adjusting.
    Drawback
    Quite unusual lag spikes will result in two “snaps”. Gamers are used to such stuff.

  2. Make physics etc. run at a different rate when localGameSpeed is different
    For instance instead of using physicsAcc += elapsed you could:
    localGameElapsed = localGameTime- localGameTimeLast;
    physicsAcc += localGameElapsed
    or physicsAcc += elapsed*localGameSpeed (localGameSpeed in seconds per second)
    Render Interpolation should make it still look smooth.
    Drawback
    Update rate might increase too much while speeding up time. Client Hardware might choke.
    (Speed change can be adjusted/capped though. See my code for an example of a cap.)
    (1000ms of lag increase would mean only 10% higher update rate at a total interpolation time of one second, though. Most people probably wouldn’t even notice this one second.)

The way I currently have it on the client won’t work, yes. But so won’t the original client physics code.

Anyway …

These should not result in a desync. I thought about it quite extensively.
Input should also work the same way you have planed. With Solution one being exactly the same and solution two just everything being slowed down/sped up for a short amount of time.
I hope you may consider option two. With option one you may need to add some restriction when and how often it is run. Option two can run all the time as small changes aren’t even noticed as they are smoothed out near instantly.

Anyway. Hope this work can be useful.
For something that might happen maybe a few times a match we sure invested a lot of time into it.

Also. You mentioned how the client physics code should be the same as the server physics code. No matter what I try I can’t get the physics code form the server to run at a consistent rate on the client. I always get some form of stutter. (I removed smoothTime)
Would be nice to know why that is.

I interpreted this statement as the client ship sending its commands to the server instantaneously, thus my question.

It doesn’t matter how you explain it because the ship looks like it’s speeding up and slowing down. If that effect can be removed or if it wouldn’t exist in a deployed system, then it’s all good. If the effect is present, it’s going to make for some odd experiences.

It’s just a quirk of how the InterpolationTest is set up. Sorry for creating this misunderstanding. The client isn’t sending anything.
When you press “4” you set the current speed of “Pos1” (Red Circle) on the client and “Pos2” (Purple Circle) on the server.
This has nothing to do with the problem or any real world application. It’s just for testing purposes.

Well which of the above two options would you prefer?

We are talking about something that wouldn’t happen very often. Maybe two or three times a match. Also I guess the team will add a “Network Warning” symbol when time is modified above a certain threshold similar to what we have in the pre-alpha now.

You switching the ping from 0ms to 1000ms every few seconds isn’t really a real world analogy.

Also, the interpolation speed isn’t final yet. Currently it’s rather low.

1 Like

I’m not going to argue about its significance. The effect is present in the system. It’s something to be aware of and to keep an eye on.

What protocol/libraries are you using for interpolation? In simulation we usually use any implementation of HLA (High Level Architecture) for avoiding problems with physics in distributed missions.
Hope you can fix last bugs!

I don’t have that stutter in the real game, but that’s because the client runs the same physics than on the server, so they’re in sync. Here in our test app, the problem is that the server runs with the physics time step but the client does not, it runs with the render step. That’s probably the cause of this stuttering. But I’m not worried about it, as that’s not the one I was trying to fix.

I understand your idea of changing the passage of time on the client to keep formations. But that’s not going to work, again, because the server is authoritative. So if the change of time affects the local player on the client, there’s going to be a mismatch ( ie. at tick 497, the player’s position is P1 on server but P2 on client ). Because the server is authoritative, the client gets corrected ( aka P1-P2 is applied to the client ) and cancels out your trick with the variable passage of time. Probably adding tons of glitches and issues to the plate.

In other words, your solution works but only if the server isn’t authoritative. We’ve already made the design choice of an authoritative server, where inputs get sent from the client and validated by the server, to avoid cheating.

In addition to cheating, the server being authoritative is necessary because the results of the physics sim might differ due to latency. For example, imagine that two ships fly into each other and bounce on the server, but due to latency, slightly miss each other and continue their course on the client. This needs to get corrected too, and the only way to do that is with an authoritative server.

1 Like

I accept these assertions, but I’m concerned about the problem of shooting someone who has gotten around a corner. In a character FPS it’s an annoyance, but won’t it be rather more of a problem with Battlescape because of the high relative velocities involved?

The simplest example I can think of is two ships flying along at zero relative velocity, but high absolute velocity (aka the same speed). WIth clients time-shifted back 100ms, it means that the 1km/s pair of ships will each see the other 100 meters behind its actual position. Even if those ships are seen free of jitter, they’re going to be firing on positions that are consistently 100 meters off. So each pilot will think that the shots are behind him, while taking damage.

The Valve technique has problems with high relative velocities - as you quickly found out. Isn’t the island/bubble thing pretty much required so as to ensure that the velocities of ships engaged in combat stay within a reasonable range? In that system, if the relative velocities are high, the odds of hitting are low and the “corner effect” is minimized. If the relative velocities are low, then the Valve technique handles everything apparently as well as it can be handled.

I know the island/bubble thing is intrusive and prohibitive in resources. But can Battlescape survive with the raw Valve technique? Or are my concerns a tempest in a teacup because 99% of the time the velocities are going to stay relatively low as fighters furball around a stationary location (point of interest)?

Will Battlescape simply have to ensure that combat takes place at stationary points of interest because of the limts of modern networking?

1 Like

Probably not just this, but fighters dogfighting will likely slow down anyway for combat to allow changes in direction. In the current prototype, if you approach at anything more than 1000m/s you pretty much get a brief shot on target then spend the next few minutes trying to turn and change vectors because we’re running mainly using “absolute velocity” at the moment, rather than relative.

Maybe this minimises the problem?

Not many corners in space. :smile:

And where there are corners (space stations, planet surfaces), the speeds involved are likely to be much lower - more in the hundreds of m/s.

After reading all this I think the simplest solution it seems to me is to just display the players ship position in the past (the position the server sends) like all other ships when the ships speed is above a certain threshold (as was suggested by playbenni). Rotation, weapon and other things could still be in the present. Like it was noted before, newtonian motion make very abrupt changes in speed or direction impossible anyway.
The only thing that really changes is the display time on the client, the server world stays unaffected, doesn’t it? The server just has to take it into account when figuring out if a shot hit and so on like it has to do anyway.

1 Like

Thanks for clarifying the physics execution question.


I see. You pretty much want smoothTimeState to do what valve does with [Entity Interpolation] (https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking#Entity_interpolation).

They seem to have a fixed distance though … somehow when I read that entry it doesn’t remind me of “InterpolationTest”.

I am trying for quite some while now but still am not able to precisely point to the source of the jitter. Hope someone finds it. (Like what constant can you change to increase/descraese the jitter)


I propose to have the local player also play in the past. Contrary to how valve does it. If you do that, slowing or speeding up client time should not have any effects.

If the client sends his localGameTime or client.snapshot.id acompaning his input the server knows exactly when, in “GameTime” these inputs where made.

The server then can still be authoritative. See in the valve article “Lag Compensation”:

The lag compensation system keeps a history of all recent player positions for one second. [snip]
Then the server moves all other players - only players - back to where they were at the command execution time. The user command is executed and the hit is detected correctly. After the user command has been processed, the players revert to their original positions.

Client physics are comparable to Input prediction


Example

Huge example inside

Player 1, 44ms to the server. He flies at constant speed.
Player 2, 166ms to the server. He has brought his ship on collision course with Player 1.
Player 3, 10ms to the server. Just watches.
Player 4, 355ms to the server. Just watches.
(no jitter)

  1. RealTime = 5.5
    server at Tick 110. 20 ticks/s. serverGameTime = 5.5
    player 1 at Tick 108 + 6ms = clientGameTime = 5.406
    player 2 at Tick 105 + 34ms = clientGameTime = 5.284
    Player 3 at Tick 108 + 40ms = clientGameTime = 5.44

  2. RealTime = 6.0 (No one has done anything collision happens at this real time)
    server at Tick 120 = serverGameTime= 6.0
    player 1 at Tick 118 + 6ms = clientGameTime = 5.906 (Player will see collision happen in 94ms)
    player 2 at Tick 115 + 34ms = clientGameTime = 5.784 (Player will see collision happen in 216ms)
    Player 3 at Tick 118 + 40ms = clientGameTime = 5.94 (Player will see collision happen in 60ms)

  3. RealTime = 6.017 (Player 2 changes course)
    Client starts to change position. At the same time he sends his inputs to the server with tickId=116
    server at Tick 120 + 17ms = serverGameTime= 6.017
    player 1 at Tick 118 + 23ms = clientGameTime = 5.923 (Player will see collision happen in 77ms)
    player 2 at Tick 116 + 0ms = clientGameTime = 5.801 (Player will see what happens in 199ms)
    Player 3 at Tick 119 + 7ms = clientGameTime = 5.957 (Player will see collision happen in 43ms)
    Player 4 at Tick 112 + 12ms = clientGameTime = 5.612 (Player will see collision happen in 388ms)

  4. RealTime = 6.094
    server at Tick 121 + 44ms = serverGameTime= 6.094
    player 1 at Tick 120 + 0ms = clientGameTime = 6.0 (Player1 will see himself collide with Player 2)
    player 2 at Tick 117 + 28ms = clientGameTime = 5.878 (Player will see collision happen in 122ms)
    Player 3 at Tick 120 + 34ms = clientGameTime = 6.034 (Player saw the collision happen 34ms ago)
    Player 4 at Tick 113 + 39ms = clientGameTime = 5.689 (Player will see collision happen in 311ms)

  5. RealTime = 6.138 (Server receives input data from Player 2 with tickId=116 )
    It will check if its plausibility, declare older ticks as invalid and calclulate new valid tick

  6. RealTime = 6.151
    Server sends out new valid Tick. TickID= 123

  7. RealTime = 6.216
    server at Tick 124 + 16ms = serverGameTime= 6.216
    player 1 at Tick 122 + 22ms = clientGameTime = 6.122 (Player saw the collision happen 122ms ago)
    player 2 at Tick 120 + 0ms = clientGameTime = 6.0 (Player2 will see himself pass Player 1)
    Player 3 at Tick 123 + 6ms = clientGameTime = 6.156 (Player saw the collission un-happen 6ms ago)
    Player 4 at Tick 116 + 11ms = clientGameTime = 5.811 (Player will see collision happen in 189ms)

Player 1 will receive corrective update 101ms after he saw the collision.
Player 2 will receive affirming update 101ms after he passed Player1.
Player 3 will receive corrective update 101ms after he saw the collision.
Player 4 will receive corrective update 105ms after he saw the collision.

Formulas used:

tick.gameTime = timeStart + tickNr * tickInterval
serverTime = realTime - timeStart
clientGameTime = realTime - delayToServer - tickInterval
serverTick = serverGameTime / tickInterval
playerTick = floor(clientGameTime / tickInterval)
playerOver = clientGameTime - ( timeStart + playerTick * tickInterval )


The server is still authoritative though. It doesn’t just take what the client is giving him but checks its outcome.
When some player changes something in the past and the server deemed that input as plausible it declares all ticks it sent out between receiving the input update and the tickID of the input update as invalid. The next tick it will send out will have valid information again. To calculate it uses the last valid tick and the dt between it and the new valid tick.
The delay for people to see the change should not be any different from any other method.

Ok ok the drawbacks are obvious.
Weirdly enough. I have created a netcode concept that results in the same amount of “lag effect”. Not matter what the ping is. (See the example) … kind of fascinating.

The “clientGameTime=realTime; clientRenderTime=realTime - delayToServer - tickInterval” method like planed by Flavien might have drawbacks too. I think one of them is that you can shoot targets that are at a past time relative to you. This is why you can’t hold formation when renderTime changes. The further you lag out. The bigger the time distance to the targets in the past.

Oh I get it now … so the server gets the “shot fired” from a player. It then sets all other players back to when the shot was fired and checks if it hits. If it does it applies effects and calculates everything back to realTime.
Still I have the feeling that every type of networking has its quirks. We are just used to them. :smiley:

Anyway I concede. :stuck_out_tongue: TIME TRAVEL IS WEEIIIIRDDDD

My stutter fix still works though! Just set back client physics to the way it was (using elapsed) and it will function as intended.
This post was all about usual network stuff and how it effects actual position. Not changing time.


I think … I hope I have said everything I wanted to say. All the best.

Thanks for discussing this. Please don’t refrain from including everyone in the discussion because of my … persistence … over enthusiasm … eh whatever.

I don’t want to force anyone to do anything.

I’m just an idealist.

4 Likes

Combat can easily take place at extremely high absolute velocities. What’s important is the relative velocities of the two ships. Consider a capsule arriving at the space station. The capsule itself ‘dogfights’ (maneuvers) at a few m/s as the two of them orbit at roughly 7800m/s. If the capsule overshoots, it drops its relative velocity to zero and comes back to make another approach.

In practice, ships will build fairly low absolute velocities when dogfighting because of the use of warp. It establishes a velocity envelope around a fight. If you’re not happy with the way the fight’s going and you’re outside of the envelope (i.e. your velocity is high enough) then you can escape on warp. Interacting is simply not possible on warp, so you’re safe.

The corner scenario is used to illustrate a basic problem found in a character avatar FPS. In a space game, the problem manifests itself in other ways. Perhaps the equivalent to the corner scenario is the matched-velocity scenario where the ships are shooting at each other. Each player sees himself shooting precisely at the other ship while each sees the other shooting behind him - and hitting him. It’s the same basic problem that is illustrated in the corner scenario.

1 Like

Correct yes, and of course absolutely true particularly in real life orbital mechanics. However, this is not how things are operating in the current Battlescape prototype (as I’m sure you know). Unless the flight mechanics change - which they probably will - I’m merely pointing out the unlikelihood of combat taking place at extreme velocities with the current setup.

Locking onto the enemy ship and using it as a reference point for your own speed would of course change this :slight_smile: The auto-formation function at the moment I find a little… tricky!