From what I've read, there's several components which go into rollback netcode and requirements.
1: Your game logic update (input/state update) has to be able to run independently of your rendering (draw stage/textures/etc) I think 7 times as fast?
2: The connections need to run over UDP p2p.
So my first question is, if my game draw is updating at once every 60 frames, does that mean my game logic, input, network read, has to update once every 8-9 fps?
And I imagine the loop looks something like this?
if(framecount%8==0){
pollnetwork();
updategamestate();
input = checkinput();
if(input){
sendinputacrossnetwork(input);
}
}
if(framecount%60==0){
render();
}
I imagine the order in which those are called is irrelevant.
So I have that in place, but where do I go from there?
Do host and peer first have to synchronise gameframes? Then every time a packet is sent between the two, they have to check what frame they're currently on, which frame they received then rewind and replay?
For example, if host is on frame 18 then won't the client frame when received be on frame 9? Because it's always updating, say 9 frames. And if the server receives client's frame 9, we go back 9 frames and redraw everything from 9 frames ago to the current state depending on what the user provided as inputs?
There's a lot I don't understand about rollback netcode and I've read a lot too but there's small implementation details that I can't figure out. I might even be missing the bigger picture.
Edit: To give more info on this, I'm doing this in C++. I'm not using a game engine, rather writing it myself in SDL with GLFW and my own network library. And in my case the state should never change during the time of the render, it's all running on one thread. And since my network function returns instantly whether or not a packet is available, I dont' have to rely on callbacks.
I have my logic update decoupled from my draw rendering. So I can separate the two.
But I think I understand it now, if I have it correct:
I have an input structure and a frame stack. Assume the frame is currently at 30
30:[peer input: null][my input: x]
29:[peer input: null][my input: y]
28:[peer input: null][my input: null]
27:[peer input: null][my input: null]
26:[peer input: null][my input: null]
Now I receive a packet with frame# 27 and an input x, because I'm already on frame 30, I now have to rewind my frames back to frame 27, inserting an input x and assume that they're going to keep pressing x until I receve a frame that says otherwise; So I rewind the framestack and insert the x where it belongs while leaving my input untouched
30:[peer input: x][my input: x]
29:[peer input: x][my input: y]
28:[peer input: x][my input: null]
27:[peer input: x][my input: null]
26:[peer input: null][my input: null]
Now I run the logic loop 4 frames simulating the state as if they had pressed x each of those frames? Then I finally draw?