Open GTASektor opened 1 year ago
Hi, @GTASektor thanks for the suggestion!
Unfortunately I'm not planning to keep making changes for now, I created this repository to study some netcode concepts and then moved on.
But, I can give you an overall idea of how to implement it.
Hi, thanks for the reply
I don't understand at all how in your example to synchronize frames from the servers given the delay, the client input is constantly ahead of the server input
I'll try to explain over a simplified example of the server and two clients A and B
Considering the point of view of Client A
, its inputs are locally simulated right away in order to avoid input lag
but due to network delay
, Client A
does not have inputs from Client B
at the current frame in order to simulate the local world correctly (let's name it frame X
) , so Client A
assumes that Client B
inputs didn't change from the last one received from the server (let's name it frame Y
) and locally simulates the world predicting inputs from Client B
from frame Y
until current frame X
. Notice that frame Y
< frame X
Some frames later (let's call frame Z
), Client A
receives Client B
inputs from frame Y+1
, two things can happen at this moment:
Client B
matches, so simulation at frame Y+1
were correctly predicted, nothing to be done hereClient B
does not match, so Client A
needs to restore the world at frame Y+1
and re-simulate the world using its inputs and Client B
inputs at each frame until current frame Z
(notice that we have original Client B
input of frame Y+1
, but other inputs until frame Z
are predicted again)(In the readme video with 200ms ping, it's easy to notice [2] happening because the other player warps from one point to other)
This process keeps going on.
I know that it's a bit tough to understand, if you have any more questions I'll be happy to answer them. It's worth mention that this doc have a more in depth explanation
My main problem is that the second client that connects to the server must receive frames from the server and the current snapshot
Let's take an example: some client is already connected and 2000 frames have passed on the server, then the next player connects, I send server frames and start the timer taking into account half the delay, but even in this case, the frames of the second client are ahead of the server frames, that is, it is very difficult for me to understand how to synchronize the frames so that they tick with a lag of 3 frames from the server frames for subsequent connections
Btw, I did a simulation on the server and it actually does not differ from the simulation on the client
Client: `public update(): void { this.timeSinceLastUpdate += Date.now() - this.lastUpdate;
const delta = FIXED_DELTA;
while (this.timeSinceLastUpdate >= delta) {
this.timeSinceLastUpdate -= delta;
this.simulateGameplayFrame(this.currentFrame);
this.currentFrame += 1;
}
this.lastUpdate = Date.now();
this.updateTimeout = setTimeout(() => this.update(), 1000 / FPS);
}
public startGame(): void {
this.room.onMessage('connected', () => {
this.inputManager = new InputManager(this.currentState.owner, ROLLBACK_WINDOW);
this.inputManager.addPlayer(this.room.sessionId);
const startInMs = 1000 - this.ping.ping / 2;
this.lastUpdate = Date.now() + startInMs;
this.updateTimeout = setTimeout(() => this.update(), startInMs);
this.currentFrame = this.currentState.frame;
this.currentInput = {
frame: this.currentFrame,
w: false,
a: false,
s: false,
d: false,
space: false,
};
document.addEventListener('keydown', (event: KeyboardEvent) => this.handleKey(event.key, true));
document.addEventListener('keyup', (event: KeyboardEvent) => this.handleKey(event.key, false));
this.currentState.players.forEach(player => {
player.inputBuffer.inputs.forEach(inputSchema => {
inputSchema.onChange = (changes: any[]) => {
this.inputManager.confirmInput(inputSchema.frame, player.id, inputSchema);
};
});
});
});
}`
server:
`setTimeout(() => {
client.send("connected", this.state.frame);
}, 1000);`
If you had the opportunity to write a small example of frame synchronization of an already running simulation, I would be very grateful, we do not touch on the topic of restoring snapshots, because it is quite simple and I have already implemented it
I run two simulations one on the server and one on the client, the server simulation exactly replicates all client actions based on input and frames
The main idea would be all clients and server roughly simulation the same frame, the actual code does this by approximately start simulating at the same time.
In order to late join and sync correctly, I'll try to use the code snippet you've sent as example, I didn't test it out:
Unfortunately, this frame synchronization code does not work
That's unfortunate :cry: , there might be some cases that I'm not aware of
If you are planning to use this implementation in an actual game, I wouldn't recommend to do it because I created this repository only to study some network concepts, the code here is far from being suitable for a production game.
I suggest you to take a look at netcode implementations backed by a big community or by a company, here some that I know:
I would like to ask you to write an example in which only one room is created without using the Start button, that is, without waiting for the host
You just need to synchronize the states of the connected players and have each new connected player immediately added to scene
You have already implemented onRemove, you need to add onAdd