IPv6 was obsolete by the mid-2000s, majorly due to the advent of roaming. It was designed on the rather fanciful assumption that its deployment would simply supersede IPv4, that every software/hardware vendor would cooperate, and we'd have a pure v6 network which would also replace the traditional L2/L3 layers.
Ofcourse legacy compatibility trumps all, along with the ubiquity of NATs and roaming and we're now just in the sunk-cost phase, being left saddled with a horribly bloated protocol (128-bit addresses was a marketing choice; not engineering) that solves no problems.
Those rates are peanuts considering that a decade ago saturating 40G, per core, was more than reasonable via standard userspace networking, with atleast a few copies in the datapath.
As someone who has implemented various transport protocols (both standard and custom) the biggest hurdle in layering atop IP will not be the gauntlet of WAN routers, surprisingly, rather consumer NAT devices.
One interesting case for a particular Netgear family of routers was that, while the traffic would survive end-to-end it was not without corruption - very specific corruption which took the form of zeroing the first 4 bytes. Given this aligns with where the src/dst ports would normally be, I suspect it was being treated as TCP/UDP albeit without the actual translation path taken.
This is really just archaic *nix world problems; the NT kernel has had actual asynchronous I/O since inception -- even 30 years later, io_uring is mere batching to the kernel upper-half (and is a carbon-copy, down to the particular terminology, of RIO)
Those numbers seem awfully low; even going via the relatively slow kernel/kernel stack, you can comfortably achieve around 2Mpps (64B) tx, per core (single flow), on ~2010 commodity hardware via standard Linux userspace APIs.
For reference, bypassing the kernel you can saturate a 10G link for ~14Mpps on a single downclocked 500MHz core with same class of hardware.
Stuck on phone at the moment; will check out the code later.
If it's any consolation: the vast, vast majority programmers should stick to single-threaded design, as is evident from all the atrocious multithreaded software out there of which 99% of the time would be faster without multiple threads (and surely far less complex)
Unless you know what you're doing, just pick the real low-hanging fruit, like throwing some threads at file block decompression.
It so happens, even though I don't like C++ that I entirely agree with the rationale behind the C++ 26 introduction of structured concurrency to the language.
About sixty years ago structured control flow was rare or non-existent in most languages. Want to do X fifteen times? Well, try setting a counter N to zero, do X, increment the counter N, and if N is less than fifteen jump back to the start of your "do-X" routine. Simple.
Oh wait, sorry, somebody else who wanted to do X is also jumping to the start of that routine, and they didn't set N so now everything is on fire.
Today your programming language has structured control flow. You write a loop, the loop does X fifteen times, it's not possible for some unrelated code to just wander into part of your loop unsuspecting and cause mayhem since it wasn't prepared to count up to fifteen. New keywords appeared like "for" and "while" and "return". It's not that somehow a new tool magically fixed the problem, but instead programmers learned to write software in a more structured way using the better tools.
Structured concurrency is the same idea again, but for concurrency.
It took some time between Dijkstra writing a letter and languages delivering the nice for-each loop we're familiar with today in many languages, and so likewise what we have today as the state of the art for structured concurrency is likely nowhere close to what will be developed over coming decades, but it's already nicer to work with that the chaos of unstructured concurrent programming.
Although not as elaborate as this, I have what one would call a "homelab" and it's for, well, testing and experimenting -- I write a lot of high-performance server/network-centric software (e.g, saturating a 100G link with 64B frames is a common test) and virtual machines just aren't suitable/capable most of the time.
Similarly, a common technique used within notably the DotA community (of which's map didn't have such a tripwire) was to analyze the replay for what were termed "fog clicks", since for whatever reason object selection is part of the command stream and those using maphack would often, intentionally or inadvertently, select objects otherwise under fog.
It is, in fact, inherent to this model. While there will be some tolerance threshold as to how far behind in the simulation a machine may fall, it still must be rather conservative (generally a few seconds), as elsewise the context (state-) sensitive inputs start frequently failing -- if I issue a command given at world-state time t, will it be meaningful/valid at state t2? The answer is where you get your threshold and it's always just a conservative approximation.
I've built and licensed a time traveling variant of this model (GGPO style) and spent years with thousands of concurrent users playing my games. And they operated just as I describe.
Company of Heroes is more of a traditional AoE style and will happily queue up unit orders for a minute or more while it attempts to reconnect or catch up.
You could probably build something better than what the AoE2 remake has now. I don't know if it'd be viable in 1998, though. Wasn't like today's constantly self-updating games; each patch risked fragmenting the community, and they only released like 2 patches across 15 years of activity. They chose something simple that'd work well enough without having to tweak it. And old PC specs, and no dedicated servers. You said it's better to disadvantage laggers than to punish everyone, but that requires some balancing to ensure it's fair enough. AoE model is always fair and can be lag-free.
Yes it relies on the players trusting each other a little to avoid extreme lag, but there are plenty of ways to ruin this kind of game besides lagging. It's not like CoD where a few useless teammates won't make a big difference, while it didn't have automated ranked play like Csgo. (but the recent DE remake does, and yes it needs better netcode)
Time-traveling netcode... I know Slippi does this, and it works great.
Are these players interacting in any way? If they aren't then it could be more tolerable, but one player being more than several seconds behind others is going to lead to a rather undesirable experience, especially in the middle of a battle (and having most of their commands dropped due to being invalid equally so)
Giving the undesirable experience to one player is strictly superior to giving it to all of them.
There just aren't many modern multiplayer games where slow players can negatively impact the experience of others, and that's because the industry has learned how terrible the experience is.
And that's for players playing in good faith on bad connections - abuse by inducing latency was a big thing in the past. Think a player that runs out the clock when they're a move away from being checkmated.
Basically the only time you'd ever want to operate the system to pause if a player fell behind is during a tournament, where fairness is more important than player experience and they know that going in. And even that, IMO, is questionable.
I'm of the opinion that it's an acceptable concession that a brief pause occurs in gameplay to permit another player to recover from transient issues (network hiccups, brief machine resource starvation, or generally: stalling) in favor of fairness rather than punishing the player too harshly for factors that are frequently out of their control.
Consider for instance the situation where-in one player's simulation enters the spiral-of-death, under the policy that you're proposing this player is effectively removed from the game; I would say this is a substantially worse trade-off -- I know that I would personally prefer some mild annoyance of brief pausing as opposed to a player leaving the game (and in session-based games, as RTS's generally are, a team-mate leaving often ruins the entire game)
Abuse is indeed a problem that most games I've seen of this nature don't address, and while there's no perfect solution, it can be quite effectively curtailed. In the systems I've designed, the basic principle is that each participating player has an allocated amount of wait time which serves as a quota that is charged while-ever the game can progress/run, but cannot, due to them being in a wait-state (connecting/loading/reconnecting/stalling/explicit pausing/whatever). There's some extra logic for handling the oscillation of wait-state.
The spiral of death trade-off does not happen as you describe.
While a client is catching up, you run the sim in a loop and don't render the game.
The deterministic simulation code is only a small part of the overall game logic, and you can run it much faster than real time.
If a client is slow enough to genuinely experience a spiral of death, the game will not be playable for them, and "mild annoyance of brief pausing" is not remotely what the other players will experience if they're forced to stay in sync.
Wait time is the common solution in older games to prevent abuse, yes. But it doesn't prevent somebody with high ping making a game run at half speed.
Go play Company of Heroes 2 with a packet loss simulator. Even as the bad client, it's totally playable. For everyone else, it's silky smooth.
I don't think you'll come back and tell me you prefer the implementation in AoE II Definitive Edition.
The simulation is, rather obviously, what's being referred to with the spiral-of-death -- it's not unusual for instance in Age of Empires II to encounter transient periods where-in steps take an order of magnitude or more than the period they're simulating on less-capable machines (due to some O(n*n)'s in the AI system).
In the end this is still a decision regarding how to handle player's falling behind; too far and they're effectively taken out of the game as they're no longer interacting within a sufficient approximation of the current state.
Under what design is "high ping" going to cause the game to run at lower "speed"? The only possibility I can see is where-in the turn period is, for some bizarre reason, also the granularity of the simulation step and you're also adapting the turn based on player latency (in aid of fairness, usually)
Having implemented such a system myself, a few times now, it has in practice performed sufficiently well.
DE is garbage in general so it's not really a fair comparison.
Transient periods is the point - for a client to enter a spiral of death, the simulation is running slowly enough that a client can't keep up, even if it's all they're doing. If a client enters this state, it's simply not going to be able to run the rest of the game, and it's out of the match regardless of what you do unless the game slows down permanently for everyone.
If you could simply wait a few seconds for them to catch up, they'd also be able to catch up without a global pause.
In any case, we're going in circles. I came to this thread to claim that "If one person lags, everyone lags." is not intrinsic to this kind of net code, and you disagreed. Company of Heroes and my own games are existence proof of my claim. I'm not really interested in arguing about it any more - millions of players can't be wrong.
Not to any meaningful degree -- inputs (from humans) permutate the state. You can, however, compute say the initial world state, revealing the map/resources/ect. Ofcourse in this case you'd may aswell just look for some sort of maphack.
Ofcourse legacy compatibility trumps all, along with the ubiquity of NATs and roaming and we're now just in the sunk-cost phase, being left saddled with a horribly bloated protocol (128-bit addresses was a marketing choice; not engineering) that solves no problems.