-
-
Notifications
You must be signed in to change notification settings - Fork 21.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NetworkedController & SceneRewinder #37200
Conversation
This is great! Client side compensation and prediction always takes some time to get running. It would be really nice if you can provide a sample project so we can test it out, the PR description is a bit too abstract to start working with. |
This sounds great! Is CharacterNetController expected to be used only for objects controllable by players, or should it also be used for other kinds of networked physics (such as RigidBodies that can be pushed around by networked players)? |
616aa8e
to
991cbc7
Compare
@asheraryam Yep, I'll submit my test sample project :) and I'll write a more in depth explanation of how it works. @Calinou This got designed mainly for situations where there is one client that controls the object and the server that has the final authority. The object can be a 2D sprite, a rigid body or a kinematic character. However, for situations where the object can be controlled by anyone (see the ball in Rocket League) the character net controller is not enough and you may need to study a specific mechanism, for your use case, to get it right. |
/// are sent in an unreliable way. | ||
int max_redundant_inputs; | ||
|
||
/// The server is behing several frames behind the client, the maxim amount |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
behing. Typo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
This is extremely feature complete and i love that you took the time to implement compression in a way that minimizes bandwidth. My only complain with this is that you are required to extend it. As a built in node, id expect it to just work out of the box and allow me to customize it only with exported properties. Is there a way we can make this happen? |
I also don't see where |
Now there is the |
I understand the need for flexibility, it's just that no other node currently works this way to my knowledge, and afaik, there's no way to message in the editor that extending this node is required. Happy to hear others' thoughts here. |
Yes, I know, the reason for this is that I need to take inputs and the snapshots information and the most polish way that I found was taking these by calling some predefined functions that must be overridden in GDScript. Using events and an API to submit these would have make things much more weird and much more prone to error; with my solution the possibility to make mistakes are much lower because the user is never involved in making this mechanism works as intended (with the only exception of |
We might be able to do this with a node configuration warning that would display until the node is extended. |
We have this messages: https://github.com/godotengine/godot/blob/991cbc75554716ab3e56a997c329acab0ab83784/modules/character_net_controller/character_net_controller.cpp#L377-L382 but we can do better using also the editor warning. |
As I am still rather unfamiliar with the inner networking bits of Godot, do we already use ENET's built-in compression tech? Do we need to do compression here as well or is it enough to simply optimize the byte stream before compression? |
@jonbonazza Yes, though we also provide FastLZ, zlib and Zstandard compression in NetworkedMultiplayerENet: Compression is currently disabled by default. I think it'd be better to enable some kind of compression by default, though we need to do some stress testing to determine which algorithm is the most suited. On paper, Zstandard is the best one, but we may be sending small packets (< 4 KB). However, Zstandard doesn't perform well on small data sizes without a pre-trained dictionary. Edit: Pull request opened (#38313). |
Optimize the stream before sending it is good for two reasons:
However, the two methods doesn't exclude each other and can be combined. |
dcd1f5b
to
4524eb1
Compare
Just chiming in to say that this should be heavily documented! Let me know if you want to talk about this sometime, I can contribute documentation provided I can get clarification on some details. |
@jknightdoeswork oh, this is really awesome! I'm in the phase of adding another feature to this and so I plan to change a bit how the controller works. But definitely I'll contact you in few weeks. |
This PR is becoming increasingly difficult to follow now that we are starting to add other features to it. Can we break the scene_rewinder stuff out into a separate pr? |
I'll write here when I've done, so you can review it once finished. I'm sorry but I can't break in two different PRs because the SceneRewinder will also change how the state check is done on the controller and would not make much sense split it. |
This change was needed as the new GDExtension bindings doesn't not support .
cd524de
to
fbbe552
Compare
Hello, I'm closing this PR as I moved all the code into its own repository that is accessible here: https://github.com/GodotNetworking/network_synchronizer In this repository you can find the version of this PR that works for the godot version 3.x and 4.0, I'll keep developing this module into that repository. |
Sorry if I'm asking about wrong stuff. |
This PR adds the possibility to synchronize a
scene
and theCharacter
s between many peers.It uses a protocol to keep in sync the clients with the server; under the hood it heals the internet problem like (Latency / Packet loss / Packet reorder / Packet Duplication / ...). Networking is complex and get it right is even more difficult; however, this controller want to be most simple to use possible but also most general purpose possible. Indeed, it's possible to use it to for 2D and 3D and with scene of any kind.
Disambiguation
NetworkedController
collects the player inputs and use those to control a character, a node, you name it. TheNetworkedController
takes care to propagate those inputs to all peers.SceneSynchronizer
make sure to keep in sync, all the specified nodes, between all the peers.How to use it
Here a sample project: https://github.com/GodotNetworking/example-project
To use it, you need to extend the
SceneSynchronizer
and create an auto-load with this script. Mine is calledNetworkSync
. Perfect, now you are ready to sync anything into your scene (more about how, below).Networked Character
Now is time to make your
Character
networked; add the nodeNetworkedController
and attach a script. Implement these callbacks:func collect_inputs(delta: float):
Collects the frame inputs.func controller_process(delta: float):
Process the frame inputs.func count_input_size(inputs: Object) -> int:
Count the input buffer size.func are_inputs_different(inputs_A: Object, inputs_B: Object) -> bool:
Compare two input buffer.At this point the
NetworkedController
is able to control the character. What is needed, however, is to specify the parameters that we need to keep in sync, for thisCharacter
; we can use theNeworkSync
to do it.My
Character
is really simple. I just need to sync the velocity and the translation, so into the_ready
function (on theNetworkedController
script), I've:Note: If your character uses an acceleration, or vertical_velocity, (or anything that is used to compute the final movement), you must register those too.
Scene synchronization
The
SceneSynchronizer
(that I'm using via the auto-loadNeworkSync
), is responsible to keep in sync the various objects into the scene.This mean that you can also keep in sync things that are not directly related to a controller; in the sample, you can find the
SyncMesh
node, that is moved via theAnimationPlayer
and uses theSceneSynchronizer
to keep it in sync across the pears.You can tell which variable you need to keep in sync using the function
SceneSynchronizer.register_variable(node, variable_name, on_change_callback = "")
.Additionally you can specify a process function, to be called in sync using:
SceneSynchronizer.register_process(node, function_name)
.Conclusion
There would be much more to talk about and to show, but for the purpose of this PR it should be enough. Please ask questions, propose improvements :) .
This work has been kindly sponsored by IMVU.
Bugsquad edit: This closes godotengine/godot-proposals#631.