Thanks for the feedback on this video, Just thought I'd give an update. This was made for a University assignment which I received 100/100 marks for. Super happy about that and also that this video has reached further than just those marking my work. I've recently started my final year of University -- so there may be more videos on this channel soon about various things I implement.
wow.. this is an amazing explanation, it really goes in deep.. usually most explanations i've seen didn't dive into details.. but you did, which is Amazing!!.. you're a legend
Wow, just... Wow! This is the best video I found that actually explains the technical details of rollback netcode, determinism and decoupling rendering from the game simulation. Most videos I've found only explain the basics concepts of rollback, and not much more than that. Bonus points for the GitHub project, I'll be checking it out soon today.
So I've been playing around with this project, to implement it into my own game, and it's going pretty well! But I get a weird bug inside the Game sim, when it comes to the actual rollback, maybe you can help me out? Inside the HandleRollbacks function, when I get the GameState to rollback, suddenly the SimPlayers of that GameState become null. We still have the GameState itself and the FrameID. Any help would be appreciated! I'll keep searching for the problem, and let you know if I find anything.
Watching someone implement rollback makes it seem within reach for me. Thanks for explaining and documenting your experience implementing it, even if it was just a simple demo in Unity (I'm aspiring to make a party game [4-8 players!] with rollback netcode in Godot (or even pure JavaScript at this point now) and I'm getting really stuck because I don't know much about determinism or networking) 😅
There’s very limited resources on implementing rollback in Unity so this video is such a godsend, awesome work! I’m trying to make a fighting game in Unity right now so this is a great reference to have, it is still really in the project but considering how hard it is to retrofit rollback that’s actually probably a good thing 🤔
Thank you for the awesome video! I am looking to implement Rollback Netcode in an indie fighting game I'm currently working on and haven't decided on a specific networking solution yet. At around 7:53 you said you didn't use any of Unitys builtin networking solutions because they either had stuff you didn't need or weren't finished yet. Can you tell me which solutions you were talking about and why specifically you didn't use each? For Example I am looking at coherence at the moment but I haven't made up my mind yet. Thank you anyway😄
I was mostly looking at Unity's Netcode for Game Objects, Mirror and Photon. They It's been a while so I couldn't tell you the exact reasons I dismissed each but in the end this was a University assignment so doing it myself gave me a better understanding of rollback system (and a better grade lol). I haven't looked into coherence too in depth but they have a section of theirs docs specifically for rollback which seems very useful: docs.coherence.io/coherence-sdk-for-unity/input-prediction-and-rollback
Hey I am trying your demo. I'd love to try to make something small during a game jam that's coming up in two days with it. When I tried to play the demo it gave me this in the console: SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall. I tried running it in the editor and a build but neither will connect with eachother.
Thank you for this video, it is very comprehensive and easy to understand. Something I don't understand is: Why have you choose to use Threads instead of using FixedUpdate for your game simulation?
It allows for my game sim to update at whatever frequency I want and for that frequency to be able to change if you end up too far behind and need to catch up, or slow the game sim down for other player to catch up. It should be possible to get something working within Unity's FixedUpdate -- just not the way I chose to go about things. My project really only uses Unity as a way to render out the gamestate. Again, not the only way to do it just the method I went for to ensure good decoupling.
This is just amazing, thank you so much for sharing! I'm definitely going to have a look at the demo. I have a question; how did you handle syncing animations across platforms? Because in the game I was making, the hitboxes are attached to the player's character, and therefore collisions would vary across platforms
They aren't synced outside of trying to keep inputs and current gamestate synced by fixing mispredictions with rollbacks. If a client finds that the remote kicked 4 frames ago, they can just have the animation on their end start on frame 4 if that makes sense. I'm not sure how Unity handles starting animations from arbitrary points but it should be possible. I think if you can keep everything synced up it should be fine. Personally I think it's cleanest to decouple any game-affecting data (hitboxes and their positions) from animation so that u can run the hitbox stuff in the simpler game simulation. I know MK has hitboxes attached to the bones of the models so there might be some better info here: ua-cam.com/video/7jb0FOcImdg/v-deo.html They also talk about handling stuff like projectiles, bunch of stuff I didn't manage to cover in my network test.
@@zacpeel-yates7276 Ah of course, if you don't attach hitboxes to the bones of the models there's no need to do that. For my game I'm thinking about making a table that has the bone positions/rotations for every frame of the animation, and then referencing that instead of using the bone's positions at runtime. This is to make sure that (1) the numbers aren't different across devices, but (2) also because of some weird bug where when I rotate/scale the character on the right side to face the other direction, the bone positions would be ever so slightly different meaning that, for example, if two players punch at the exact same time at a specific distance from one another, only the player on the left will get hit. Also I'm glad to hear you passed your assignment with flying colours! (how could you not, this is just amazing). I wish you the best for your future
@@djjimmaster8261 Thanks! Saw some of the stuff on your channel and it's looking good! Having a pre-made table of positions for each frame in the animation that you can reference is a good idea actually. Maybe could build some kind of editor script that lets you take an animation and convert it to a table of values that is serialized to a file for reference at runtime. Best of luck with your implementation!
@@zacpeel-yates7276 Thanks! I'm not very good at doing editor stuff yet (am quite new to Unity) so I was just thinking of playing the animation during runtime lol. But maybe I should try looking into making an editor script for it, would be an interesting challenge!
Thanks for all the amazing info, this stuff is great and its really hard to find concrete material for this topic like this video. Hope it's okay for me to ask, I've been wondering about the fix tick rate with 60fps, what happens if this isn't consistent because of low specs or other issues? I guess on a local environment everything would slow down, but on an online environment would you have to send a message with the FPS rate for both players and then set it to the lowest FPS rate for both? Otherwise one could play at 60fps and another at 30fps for example if their PC can't handle it, not sure if I am missing something obvious.
This is known as 'rift' and will lead to one-sided rollbacks for the player with a higher frame-rate as inputs will be arriving to them late. Their inputs will arrive to the opponent ahead of time as the opponent is lagging behind, meaning the game will never be predicting ahead or rolling back. While handling this was outside of the scope of my implementation, having the game simulation and rendering decoupled means hopefully we can hit 60 game logic updates per second regardless of the visual frame-rate, and my code can handle changing update rates already in order to simulate multiple game logic updates within a render frame when correcting mispredictions . If the CPU is overheating and throttles itself though, it will slow down regardless. If it's only temporary we can rewind the gamestate back to the last point the players were synced, or try to sync in between (player A is on frame 12, player B is lagging behind on frame 8 - should try to sync both players on frame 10 ). MKX does this by lengthening the frames of the player who is ahead slightly in order to allow for the other player to catch up, then everything is put back to normal. If player As frames are briefly taking 20ms (50 FPS) instead of 16.67ms (60FPS) its gonna be pretty unnoticeable, but you net a frame of catchup every 5 frames. If it's consistently running at a lower framerate though (especially something like 30FPS vs 60FPS) its not gonna be a fun experience I'd imagine. Easiest 'solution' would be to force both players to be at the lowest update rate as you said, but then you either lose precision in the simulation - which will cause issues -or have players play in slow-motion - which is not fun. At that point its more of a question of optimization or ensuring ur minimum recommended specs for the game can consistently hit 60FPS on low graphics settings. Eventually though you would just need to accept the players aren't able to have a fair game under the current conditions and disconnect them for quality of service. (MKX does this at about 300 ping, not sure how they factor rift in) Here's a link to Tony Cannon's implementation ( GGPO, C++) where they handle this problem: github.com/pond3r/ggpo/blob/master/src/lib/ggpo/timesync.cpp Here's the excellent Core-A-Gaming talking with Tony about rift (timestamped, but the whole video is good): ua-cam.com/video/0NLe4IpdS1w/v-deo.html PS. Of course its ok for you to ask! Hope this helps.
Question: How do you handle inputs lost due to packet loss? This assumes you are guaranteed to transfer inputs over the connection, and are using UDP instead of TCP. Do you simply let the sender know that nothing has been received, causing the sender to send the entire game state until it is synced again? Edit: After further research, I found a solution to simply send over the previous frames along with the current frame, if packet loss is detected. Though, would be good to see if you have any other solutions to this as well.
Sending previous inputs let's you fix incorrect predictions due to lost inputs. But with too high packet loss it won't be stable. You only need to send previous inputs up to your max allowed number of rollback frames so it shouldn't cause too much additional network traffic. It's not a problem I've tried to implement a solution for personally though. Best of luck.
@zacpeel-yates7276 Oh yeah for sure, and thanks for the reply. Didnt expect to get a reply on a year old video to be honest LOL. I definitely will limit the accepted number of rollback frames and maybe try to add in delay or something if it exceeds that, and probably disconnect if the lag is too much. If each frame is 4 or so bytes then it should hopefully be ok, i think, im a beginner at this so im not really sure but 4*10 bytes doesnt sound like a lot to transmit. I really do wonder how AAA studios do it... either way this video is a great resource though so thanks for that too!
GGPO was originally written in C++ so you may be able to port it over, and there are existing plugins for UE4 if you don't want to roll your own: github.com/BwdYeti/GGPOUE4
@@zacpeel-yates7276 im actually making a fighting game in unreal, but i know almost nothing about multiplayer. so its been a struggle. thanks for the info.
I havent finished but this seems to be plagiarized from Core-A gaming's video on the subject. Most of the content, demos, and phrasing is the same... Please credit them and i hope you asked before you used their video as the basis for your own... Edit: ah i see that you did credit them as a source in the description, but still i think the credit should be clearer in the video
I appreciate the feedback. I did indeed use Core-A-Gaming's rollback demo footage from Punch Planet. In retrospect I should have been clearer on my source as I was with the GDC talks. Core-A-Gaming's video is made to inform players of the benefits of rollback to players, mine does need to do that as an introduction for people who don't know about rollback (e.g. my Uni lecturer marking my assignment) but is mostly aimed at developers + discussing implementation details. Outside of that footage I don't think it's fair to say the content, demos or phrasing are the same. Core-A-Gaming's video is not the basis of my video, though part of it was used to provide context, as with other existing videos from GDC and others. My video was made to showcase my own rollback implementation for a University assignment, and my use of footage would fall under Fair Use. If I (re)made the video today, I would do a lot of things differently. I didn't expect it to get the attention it did but I'm thankful for all the feedback from everyone. One day I'll get around to making another video :D
Thanks for the feedback on this video, Just thought I'd give an update.
This was made for a University assignment which I received 100/100 marks for.
Super happy about that and also that this video has reached further than just those marking my work.
I've recently started my final year of University -- so there may be more videos on this channel soon about various things I implement.
Nice!! You deserve it. This is absolutly the best video I have seen on the subject and super well presented.
wow.. this is an amazing explanation, it really goes in deep.. usually most explanations i've seen didn't dive into details.. but you did, which is Amazing!!.. you're a legend
Wow, just... Wow!
This is the best video I found that actually explains the technical details of rollback netcode, determinism and decoupling rendering from the game simulation.
Most videos I've found only explain the basics concepts of rollback, and not much more than that.
Bonus points for the GitHub project, I'll be checking it out soon today.
Let me know how you got on, I can try to answer any questions you have.
So I've been playing around with this project, to implement it into my own game, and it's going pretty well!
But I get a weird bug inside the Game sim, when it comes to the actual rollback, maybe you can help me out?
Inside the HandleRollbacks function, when I get the GameState to rollback, suddenly the SimPlayers of that GameState become null. We still have the GameState itself and the FrameID.
Any help would be appreciated!
I'll keep searching for the problem, and let you know if I find anything.
Watching someone implement rollback makes it seem within reach for me. Thanks for explaining and documenting your experience implementing it, even if it was just a simple demo in Unity (I'm aspiring to make a party game [4-8 players!] with rollback netcode in Godot (or even pure JavaScript at this point now) and I'm getting really stuck because I don't know much about determinism or networking) 😅
There’s very limited resources on implementing rollback in Unity so this video is such a godsend, awesome work! I’m trying to make a fighting game in Unity right now so this is a great reference to have, it is still really in the project but considering how hard it is to retrofit rollback that’s actually probably a good thing 🤔
This video was awesome. Thank you for the explanation, It helps a lot. I'm going to check out the demo project.
Thanks for the feedback! Let me know if you have any further questions.
This video is a lifesaver! Thank you.
What a divine video! Love it!
So cool !
Cool Video!
Thank you for the awesome video!
I am looking to implement Rollback Netcode in an indie fighting game I'm currently working on and haven't decided on a specific networking solution yet.
At around 7:53 you said you didn't use any of Unitys builtin networking solutions because they either had stuff you didn't need or weren't finished yet.
Can you tell me which solutions you were talking about and why specifically you didn't use each?
For Example I am looking at coherence at the moment but I haven't made up my mind yet.
Thank you anyway😄
I was mostly looking at Unity's Netcode for Game Objects, Mirror and Photon. They
It's been a while so I couldn't tell you the exact reasons I dismissed each but in the end this was a University assignment so doing it myself gave me a better understanding of rollback system (and a better grade lol).
I haven't looked into coherence too in depth but they have a section of theirs docs specifically for rollback which seems very useful: docs.coherence.io/coherence-sdk-for-unity/input-prediction-and-rollback
Hey I am trying your demo. I'd love to try to make something small during a game jam that's coming up in two days with it. When I tried to play the demo it gave me this in the console: SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall.
I tried running it in the editor and a build but neither will connect with eachother.
very nice.
Thank you for this video, it is very comprehensive and easy to understand.
Something I don't understand is: Why have you choose to use Threads instead of using FixedUpdate for your game simulation?
It allows for my game sim to update at whatever frequency I want and for that frequency to be able to change if you end up too far behind and need to catch up, or slow the game sim down for other player to catch up. It should be possible to get something working within Unity's FixedUpdate -- just not the way I chose to go about things. My project really only uses Unity as a way to render out the gamestate. Again, not the only way to do it just the method I went for to ensure good decoupling.
Cool viDeo
This is just amazing, thank you so much for sharing!
I'm definitely going to have a look at the demo. I have a question; how did you handle syncing animations across platforms? Because in the game I was making, the hitboxes are attached to the player's character, and therefore collisions would vary across platforms
They aren't synced outside of trying to keep inputs and current gamestate synced by fixing mispredictions with rollbacks. If a client finds that the remote kicked 4 frames ago, they can just have the animation on their end start on frame 4 if that makes sense. I'm not sure how Unity handles starting animations from arbitrary points but it should be possible. I think if you can keep everything synced up it should be fine.
Personally I think it's cleanest to decouple any game-affecting data (hitboxes and their positions) from animation so that u can run the hitbox stuff in the simpler game simulation.
I know MK has hitboxes attached to the bones of the models so there might be some better info here: ua-cam.com/video/7jb0FOcImdg/v-deo.html
They also talk about handling stuff like projectiles, bunch of stuff I didn't manage to cover in my network test.
@@zacpeel-yates7276 Ah of course, if you don't attach hitboxes to the bones of the models there's no need to do that.
For my game I'm thinking about making a table that has the bone positions/rotations for every frame of the animation, and then referencing that instead of using the bone's positions at runtime. This is to make sure that (1) the numbers aren't different across devices, but (2) also because of some weird bug where when I rotate/scale the character on the right side to face the other direction, the bone positions would be ever so slightly different meaning that, for example, if two players punch at the exact same time at a specific distance from one another, only the player on the left will get hit.
Also I'm glad to hear you passed your assignment with flying colours! (how could you not, this is just amazing). I wish you the best for your future
@@djjimmaster8261 Thanks! Saw some of the stuff on your channel and it's looking good!
Having a pre-made table of positions for each frame in the animation that you can reference is a good idea actually.
Maybe could build some kind of editor script that lets you take an animation and convert it to a table of values that is serialized to a file for reference at runtime.
Best of luck with your implementation!
@@zacpeel-yates7276 Thanks! I'm not very good at doing editor stuff yet (am quite new to Unity) so I was just thinking of playing the animation during runtime lol. But maybe I should try looking into making an editor script for it, would be an interesting challenge!
Thanks for all the amazing info, this stuff is great and its really hard to find concrete material for this topic like this video.
Hope it's okay for me to ask, I've been wondering about the fix tick rate with 60fps, what happens if this isn't consistent because of low specs or other issues? I guess on a local environment everything would slow down, but on an online environment would you have to send a message with the FPS rate for both players and then set it to the lowest FPS rate for both? Otherwise one could play at 60fps and another at 30fps for example if their PC can't handle it, not sure if I am missing something obvious.
This is known as 'rift' and will lead to one-sided rollbacks for the player with a higher frame-rate as inputs will be arriving to them late. Their inputs will arrive to the opponent ahead of time as the opponent is lagging behind, meaning the game will never be predicting ahead or rolling back.
While handling this was outside of the scope of my implementation, having the game simulation and rendering decoupled means hopefully we can hit 60 game logic updates per second regardless of the visual frame-rate, and my code can handle changing update rates already in order to simulate multiple game logic updates within a render frame when correcting mispredictions .
If the CPU is overheating and throttles itself though, it will slow down regardless. If it's only temporary we can rewind the gamestate back to the last point the players were synced, or try to sync in between (player A is on frame 12, player B is lagging behind on frame 8 - should try to sync both players on frame 10 ).
MKX does this by lengthening the frames of the player who is ahead slightly in order to allow for the other player to catch up, then everything is put back to normal. If player As frames are briefly taking 20ms (50 FPS) instead of 16.67ms (60FPS) its gonna be pretty unnoticeable, but you net a frame of catchup every 5 frames.
If it's consistently running at a lower framerate though (especially something like 30FPS vs 60FPS) its not gonna be a fun experience I'd imagine. Easiest 'solution' would be to force both players to be at the lowest update rate as you said, but then you either lose precision in the simulation - which will cause issues -or have players play in slow-motion - which is not fun. At that point its more of a question of optimization or ensuring ur minimum recommended specs for the game can consistently hit 60FPS on low graphics settings. Eventually though you would just need to accept the players aren't able to have a fair game under the current conditions and disconnect them for quality of service. (MKX does this at about 300 ping, not sure how they factor rift in)
Here's a link to Tony Cannon's implementation ( GGPO, C++) where they handle this problem: github.com/pond3r/ggpo/blob/master/src/lib/ggpo/timesync.cpp
Here's the excellent Core-A-Gaming talking with Tony about rift (timestamped, but the whole video is good): ua-cam.com/video/0NLe4IpdS1w/v-deo.html
PS. Of course its ok for you to ask! Hope this helps.
Question: How do you handle inputs lost due to packet loss? This assumes you are guaranteed to transfer inputs over the connection, and are using UDP instead of TCP. Do you simply let the sender know that nothing has been received, causing the sender to send the entire game state until it is synced again?
Edit: After further research, I found a solution to simply send over the previous frames along with the current frame, if packet loss is detected. Though, would be good to see if you have any other solutions to this as well.
Sending previous inputs let's you fix incorrect predictions due to lost inputs. But with too high packet loss it won't be stable. You only need to send previous inputs up to your max allowed number of rollback frames so it shouldn't cause too much additional network traffic. It's not a problem I've tried to implement a solution for personally though. Best of luck.
@zacpeel-yates7276 Oh yeah for sure, and thanks for the reply. Didnt expect to get a reply on a year old video to be honest LOL. I definitely will limit the accepted number of rollback frames and maybe try to add in delay or something if it exceeds that, and probably disconnect if the lag is too much.
If each frame is 4 or so bytes then it should hopefully be ok, i think, im a beginner at this so im not really sure but 4*10 bytes doesnt sound like a lot to transmit.
I really do wonder how AAA studios do it... either way this video is a great resource though so thanks for that too!
Wow
Wish could do this in inreal engine.
GGPO was originally written in C++ so you may be able to port it over, and there are existing plugins for UE4 if you don't want to roll your own:
github.com/BwdYeti/GGPOUE4
@@zacpeel-yates7276 im actually making a fighting game in unreal, but i know almost nothing about multiplayer. so its been a struggle. thanks for the info.
I havent finished but this seems to be plagiarized from Core-A gaming's video on the subject.
Most of the content, demos, and phrasing is the same...
Please credit them and i hope you asked before you used their video as the basis for your own...
Edit: ah i see that you did credit them as a source in the description, but still i think the credit should be clearer in the video
I appreciate the feedback.
I did indeed use Core-A-Gaming's rollback demo footage from Punch Planet. In retrospect I should have been clearer on my source as I was with the GDC talks.
Core-A-Gaming's video is made to inform players of the benefits of rollback to players, mine does need to do that as an introduction for people who don't know about rollback (e.g. my Uni lecturer marking my assignment) but is mostly aimed at developers + discussing implementation details.
Outside of that footage I don't think it's fair to say the content, demos or phrasing are the same. Core-A-Gaming's video is not the basis of my video, though part of it was used to provide context, as with other existing videos from GDC and others. My video was made to showcase my own rollback implementation for a University assignment, and my use of footage would fall under Fair Use.
If I (re)made the video today, I would do a lot of things differently. I didn't expect it to get the attention it did but I'm thankful for all the feedback from everyone. One day I'll get around to making another video :D