Skip to content

Fix starting order for RollbackSynchronizer#284

Merged
elementbound merged 16 commits intofoxssake:mainfrom
TheYellowArchitect:rollback-synchronizer-start-fix
Nov 19, 2024
Merged

Fix starting order for RollbackSynchronizer#284
elementbound merged 16 commits intofoxssake:mainfrom
TheYellowArchitect:rollback-synchronizer-start-fix

Conversation

@TheYellowArchitect
Copy link
Copy Markdown
Contributor

@TheYellowArchitect TheYellowArchitect commented Sep 22, 2024

Solves #260 and #268 by fixing input initialization.

Also gets rid of the await 1 frame hack for 2 seperate classes (BrawlerController.gd/player.gd) in order to await for input authority to be set before process_authority, so this awaiting a frame logic is moved to RollbackSynchronizer since in most games, input authority is set in _ready or something similar.

May also solve the reported problem of the first 2 ticks, having NPCs spinning. Haven't seen it in a project of mine, but it may solve it because this PR addresses the first _earliest_input being set properly

var _inputs: Dictionary = {}
var _latest_state: int = -1
var _earliest_input: int
var _started_at_tick: int = -1
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable ultimately ended up being unused, but its useful to keep so as to know when an avatar joined/started.


if (await_first_frame):
await get_tree().process_frame
process_authority()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After await, it is basically guaranteed the input authority is set, so process_authority can be safely invoked


if tick < earliest:
_logger.warning("Tried to load tick %s which is earlier than the earliest we have recorded (%s)
Try increasing the history limit." % [tick, earliest])
Copy link
Copy Markdown
Contributor Author

@TheYellowArchitect TheYellowArchitect Sep 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug comment, to confirm #260 is fixed. Place this message on main branch, and you will see it goes from 0 to current. I will remove this message once this PR is reviewed/approved

_snap_to_spawn()

# TODO: What if the RollbackSynchronizer had a flag for this?
# Wait a frame so Input has time to get its authority set
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And that's what I did :P

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out this is not needed at all, we can just defer the process_settings() call in RollbackSynchronizer - running it in the next idle time, usually at the end of the current _process().

@TheYellowArchitect
Copy link
Copy Markdown
Contributor Author

TheYellowArchitect commented Sep 23, 2024

EDIT: The below is arguments against and for, the await 1 frame logic, ultimately ending in for keeping things as the code in this PR is.


Btw the "await 1 frame" logic could be skipped entirely. It is only useful if the Input authority is set in the same PackedScene as RollbackSynchronizer. The tree order in Godot is top to bottom. So if the input authority is set in _ready, then that Input node must be above RollbackSynchronizer, so Input's _ready fires before RollbackSynchronizer's.

At forest-brawl, the input authority isn't set at _ready of root brawler or at _ready of Input, but outside, at the spawner:

func _spawn(id: int) -> BrawlerController:
	var avatar = player_scene.instantiate() as BrawlerController
	avatars[id] = avatar
	avatar.name += " #%d" % id
	avatar.player_id = id
	spawn_root.add_child(avatar)
	
	# Avatar is always owned by server
	avatar.set_multiplayer_authority(1)

	print("Spawned avatar %s at %s" % [avatar.name, multiplayer.get_unique_id()])
	
	# Avatar's input object is owned by player
	var input = avatar.find_child("Input")
	if input != null:
		input.set_multiplayer_authority(id)
		print("Set input(%s) ownership to %s" % [input.name, id])
	

So as it is, without the await 1 frame, all _ready trigger, and then input authority is set -> which ofc bugs.
Ideally, input authority would be set inside _ready of Input node. I can expand this PR for this, and to remove the await 1 frame, but that would make setting input authority outside the PackedScene impossible, so I suggest keeping this PR as is.

@elementbound
Copy link
Copy Markdown
Contributor

Updated PR, turns out the single-frame wait is not needed at all. Also explained it under #260 (comment)

@TheYellowArchitect
Copy link
Copy Markdown
Contributor Author

TheYellowArchitect commented Nov 13, 2024

There is a weird "bug" which I have to mention. If a client joins for the first full second, sometimes, the client hovers.
Here is a video example of this: https://youtu.be/BZGODoPt_6w
I tried removing the deferred call and straight up adding an await, but the result was the same.
This shouldn't block the merge, because without this PR there is straight up desync lol

To confirm this bug isn't a regression, I checked out to commit 20c5bfd
It was very rare compared to this commit, but I did manage to reproduce it at that commit too. Though the "disabled hovering" didn't last as long as latest commit.

I assume it has something to do with is_initialized and should be visible = false until then? idk since is_initialized was added on the latest commits, but this start hover/delay didn't last that long on the previous commit.

P.S. All testing was done with 200ms, and input broadcast disabled.

@TheYellowArchitect
Copy link
Copy Markdown
Contributor Author

TheYellowArchitect commented Nov 13, 2024

On the addition of is_initialized, since its a boolean, might as well convert it to integer as it was (started_at_tick) to track which tick the rollback synchronizer started. The default value being -1. So the condition comparison is if started_at > -1

@elementbound elementbound merged commit 04e8a7c into foxssake:main Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants