Anyway. I only have unfinished attempts at low-latency netcode and rollback, so can't say I'm speaking from solid experience. But I would doubt that engines implement rollback netcode for you. Essentially the game needs to be structured in a way to accomodate storage of game state as snapshots. And it needs to decide how to incorporate messages that arrive late.
The comment was that (surprisingly) all games are single threaded and feel very turn based. Even real-time games.
I also don't know what you mean by "games are single threaded and feel very turn based". Games are usually not single threaded (insofar as most games run on multiple OS threads). If you want to say they feel single threaded, then it might be because the screen emits one frame after another, and you can influence the next frame by your action? But I don't know how that is an interesting insight and it doesn't seem to have anything to do with how games stay in sync.
You might have something interesting to say, but I wasn't able to learn anything from your post. Add to that the slightly accusing tone of it ("again conflating") I can't help but be annoyed.
But anyway, this is like the most basic insight and doesn't touch what I said at all. It does not explain how games stay in sync, unless you go back to shitty 90's lockstep netcode.
As I said in my first comment.
Except because of latency, it's like taking turns when you may be ahead of other players in turns or behind other players and the game does rollbacks to make the turns make sense once they've all arrived and how many turns ahead/behind you are is also dynamic.
It ends up having a very real affect on the actual game mechanics. In CS:GO a player peaking out from an obstacle has the advantage over the player waiting for them to pop out.
yes, originally it was developed as turn-based and I often wonder if that's one reason why the animations are sooo satisfying. But could be that they simply had great animators.
The really simple way is to just pass a delta milliseconds to each system so it can simulate the right amount of time.
But yeah, it was wild how DS2 at 60fps fundamentally altered a lot of things like weapon durability and jump distance.
while (!exitRequested) {
player.updateState();
someCharacter.updateState();
someOtherCharacter.updateState();
}
you could in theory make this kind of updates in parallel but then the entire game becomes a non-deterministic chaos and trying to deal with synchronising threads in a context like this is such a nightmare and I'm sure intractable performance-wise. did anyone even try this, ever?bottom line, real-time or turn-based, a piece of code needs to execute before or after another, not at the same time.
the order in which things take their "turn" each frame becomes very important the more complex the game btw, so even the order in which things execute serially cannot be entirely arbitrary. usually for things that depend on other things to update their state in order to accurately update their own state. which is a lot of things in every game. for example, you wanna update the text on the GUI that says how much gold the player has. you'll update the text after everything that could have influenced the gold this frame has updated (i.e. at the end of the frame). player input state (keyboard input e.g.) is updated at the beginning of the frame before you make the player's character do anything based on input.
particular stuff can be parallelized or turned into coroutines that "update a little bit each loop" so as to not kill performance. like pathfinding, a character needs to go from point A to point B, he doesn't really need to find the whole path now. a partial path while a separate thread calculates the entire path can do. or just make him think a bit while the pathfinding thread finds a path, the advantage is characters thinking about their actions is also realistic :P
I think it depends on the granularity.
Coarse-grained parallelism is already common: some things like AI (like your example), Physics, Resource Management, Shader Compilation, Audio and even Netcode are already commonly run in separate threads.
However you won't see the updateInputs(), all the updateState() and sometimes even render() running in parallel for two reasons: first because it's often cheaper and easier/simpler to run in the main thread than dispatching async jobs anyway. Second because each operation often depends on the previous ones, and you can't wait until the next frame to take it into account: you often want instant feedback.
However these things can in theory be run in parallel without becoming chaos. ECS is often very parallelizable: you can run multiple Systems in different threads, as long as the output of one System is not a dependency of another running at the same time. You could also process multiple components of a system in multiple threads, but that would negate ECS main advantage: being cache-friendly by virtue of running in a single thread.
https://www.gdcvault.com/play/1022186/Parallelizing-the-Naug...
>for example, you wanna update the text on the GUI that says how much gold the player has. you'll update the text after everything that could have influenced the gold this frame has updated (i.e. at the end of the frame).
Modern game engines are pipelined; you render the previous frame logic. In the talk aforementioned, they show a three stages deep pipeline looking like this
[FRAME] [FRAME+1] [FRAME+2]
----------------------------------------------
[LOGIC] [LOGIC+1] [LOGIC+2]
[RENDER LOGIC] [RENDER LOGIC+1]
[GPU RENDERING]
each stage is independent and doesn't require syncing. they call that "frame centric design". for {
a[i] = something;
b[i] = something;
c[i] = a[i] + b[i]; // can only do a and b at the same time because c depends on them
}
// handle a[0],b[0]
for {
a[i] = something;
b[i] = something;
c[i-1] = a[i-1] + b[i-1]; // can do all 3 at the same time because no deps.
}
// handle c[last]
optimization I saw in a talk about how CPUs can do many instructions at once if they don't depend on each other.I was unaware of how something like this could play into game engines at the loop level, thanks for the link I'll watch it asap.
You press a button. It takes 1 frame for the signal from your USB device to get polled through the OS into your engine. Then it takes 1 frame for the input to affect the logic. Then it takes 1 frame for that change in logic to get "prepared" for rendering. Then it takes 1 frame for the GPU to draw the result. And depending on your video buffering settings and monitor response time, you're still adding a frame until you see the result.
If you're running 60 frames per second, that's an abysmal 83 milliseconds lag on every player input. And that's before network latency.
But these days it's hard enough to convince people that 'a cinematic 30fps' really really sucks compared to 60 (or better), and there's an even smaller number of gamers/devs who seem to notice or care about latency issues.
A system would try to apply damage to a ship that was already destroyed.
It taught me that you often have to flag things and then do a cleanup phase at the end. So destroyed = true but don’t outright delete the entity until the end of the “turn.”