Kehom / GodotAddonPack

A collection of pure GDScript addons for Godot
http://kehomsforge.com
MIT License
190 stars 15 forks source link

[Network] Non player entity snapshot correction #20

Open yuraj11 opened 4 years ago

yuraj11 commented 4 years ago

I am working on moveable platform in 2D which has constant velocity and uses StaticBody. The issue is that corrections keep incrementing even though I applied new corrected position. I am running this code on both server and client.

The logic is following:

func _ready() -> void:
 uid = name.hash()
 network.snapshot_data.add_pre_spawned_node(MovingPlatformSnapshot, uid, self)
 # load platform points

func _physics_process(delta: float) -> void:
 ####
 if correction_needed:
  position = correction.position
  next_stop_index = correction.next_stop_index
  ...
  for _i in network.snapshot_data.get_prediction_count(uid, MovingPlatformSnapshot):
   update_platform(delta)
 #### 
update_platform(delta)
network.snapshot_entity(MovingPlatformSnapshot.new(uid, 0).from_node(self))

func update_platform(delta: float) -> void:
    # velocity is constant calculated from next_stop_index which is next point where should platform stop but it is same on server and client
    position += velocity * delta

MovingPlatformSnapshot contains position and next_stop_index

The position in corrected always differ in very similar numbers like 3 pixels difference. Also I have observed same issue with your demo project - glowprojectile.gd it keeps correcting. Maybe there's something missing in the addon like we needed for player entities (correct_in_snapshot) ? I don't even use anything advanced with physics it's just simple position and once it is corrected it should be sync with server.

Kehom commented 4 years ago

The correct_in_snapshot can be used with non player entities and it kind of should be used. The topic Prediction Without Input Data in the tutorial showcases how to re-simulate non player entities.

Now, corrections will occur, specially when dealing with floating point math. It is possible to incorporate an error margin into the comparisons (check topic Floating Point Comparison) which should reduce the number of corrections. Increasing the margin will reduce corrections but may result in slightly offset states. So, if not using the automatic margin calculation, the value must be tweaked.

That said, corrections are not bad if they don't result in visual glitches.

yuraj11 commented 4 years ago

correct_in_snapshot second parameter is InputData - what it should be in this case?

Kehom commented 4 years ago

Ohh damn. Silly me! I should not write answers when half asleep! I will think about something to allow corrections of non player entities. More specifically, to locate the correct local snapshot. It will probably give an alternative way to perform the same task for entities that use input data.

Are the corrections resulting in visual glitches in your case? If that's the case then I will probably have to move this up in the priority list.

yuraj11 commented 4 years ago

On the left is client position and on the right is server corrected position:

(-192, 821.666443) (-192, 831.666565)   # start
(-192, 819.999756) (-192, 829.999878)
(-192, 818.333069) (-192, 828.333191)
(-192, 816.666382) (-192, 826.666504)
(-192, 814.999695) (-192, 824.999817)
(-192, 813.333008) (-192, 823.33313)
(-192, 811.666321) (-192, 821.666443)    # <== shifted
(-192, 809.999634) (-192, 819.999756)
(-192, 808.332947) (-192, 818.333069)
(-192, 806.66626) (-192, 816.666382)
(-192, 804.999573) (-192, 814.999695)

as you can see the positions are correct but they are somehow shifted and not in order

Kehom commented 4 years ago

That is normal and the difference will be even bigger when latency increases. That is a byproduct of locally running the simulation. In a way, the client will always be ahead the most recently received data. Think about this. When server dispatches the snapshot data, both server and client continue to simulate the game. Because it takes some time for the data to be delivered, both machines will be "in the future" when compared to that data set.

That is the reason I use input signature to find the local snapshot, rather than the snapshot signature itself.

I'm now considering some options to allow client code to correct local snapshots in a similar way it is done when input data is available. The funny thing, when I implemented the correct_in_snapshot I did indeed think "OK, I already have means to re-simulate non player entities so it should be enough to" but completely forgot that input data is not available to those entities. Ohh well...

yuraj11 commented 4 years ago

I understand that client is ahead of server but still you can stamp what you send to server and then check in history buffer If position send at certain time was valid and If not then do corrections but do not validate actual data only validate history.

Kehom commented 4 years ago

I did think about sending extra information to facilitate things. The thing is, regardless of what data is given, because the client is ahead of the delivered data, there will be local state (a few snapshots) that will be incorrect in case the server disagrees with the client. Correcting a single local snapshot is not enough to prevent visual glitches, that's why I had to provide means to perform this correction for each re-simulated step.

Unfortunately I didn't think though and completely forgot about entities that don't need input data.

Now, just to make things clear, when the correction is requested on the client side, the comparison was done with the snapshot that was in the past, the one that corresponds to the used input, not the most recent local one.

I'm currently evaluating some options that I have to provide the necessary information to perform the local snapshot corrections in a relatively simple way. The simplest way I thought would break compatibility with current code, which I absolutely don't want to do.