If the guest is slow to respond, the host would enter a busy loop
polling for the guests to be ready. Mitigate the CPU load by sleeping
for 50ms when guests are not yet ready.
Convert the RAIIsocket to a simple SOCKET before passing it to FD_SET.
Otherwise, the build fails with:
```
similar/main/net_udp.cpp: In function 'int {anonymous}::udp_general_packet_ready(dcx::{anonymous}::RAIIsocket&)':
similar/main/net_udp.cpp:969:2: error: use of deleted function 'bool dcx::{anonymous}::RAIIsocket::operator==(T) const [with T = long long unsigned int]'
969 | FD_SET(sock, &set);
| ^~~~~~
similar/main/net_udp.cpp:493:29: note: declared here
493 | template <typename T> bool operator==(T) const = delete;
| ^~~~~~~~
```
Compiler error messages are generally better when reporting a misuse
that fails a requires() versus reporting a misuse that fails a
std::enable_if. In some cases, this also makes the code clearer, and
avoids the need for dummy template parameters as a place to invoke
std::enable_if.
Instead of sliding the entire queue down one element at a time, move the
non-expired elements in one step, and wipe all the trailing elements
in a single pass.
The only values for any given player are true/false, so use a bitset
instead of a byte per player. Some implementations may use a uint64_t
internally, negating the space savings. Even so, this version is
an improvement for requiring the use of playernum_t as an index.
The function had one caller, which always passed `0`. Inline that.
Next, observe that `sent` is only ever modified `if (!(Game_mode &
GM_NETWORK))`. As a multiplayer function, `multi_send_robot_frame`
should never be called in single-player, so this test should always be
false. Delete it, and observe that `sent` is now `const`.
Remove unused return value of `multi_send_robot_frame`.
Instead of passing a bare `int` named `secret_flag`, define it as an
`enum class : uint8_t` to name the two special values.
Rework the passing of this value, to deal with some confusing
inconsistencies when reading the code.
Before this change:
In D1:
- Multiplayer will always go to the secret level, regardless of which
exit door the player used.
In D2:
- Flying through a D1 secret exit in multiplayer shows the on-HUD error
"Secret Level Teleporter disabled in multiplayer!", and does not exit
the level. This is at best confusing, and at worst dangerous, since
D1 secret exits are only available during the countdown, so the player
has little time to realize that the normal exit must be used instead.
- Like D1, multiplayer will request to go to the secret level regardless
of the exit used. Unlike D1, the caller ignores the flag and always
advances to the next regular level.
After this change:
- No observable differences for the player in-game. The questionable D2
secret exit handling for D1 is retained.
- The code makes clearer that secret exits do not work in D2
multiplayer, by way of `#if defined(DXX_BUILD_DESCENT_I)` guarding the
existence of the parameter and all updates to it.
All callers except one want the `lite` version of the request. Switch
from a boolean that is selected inside the function to a reference that
is defaulted to `lite`. Override that argument to the heavy version in
the one caller that needs it.
Using `netplayer_info` in `UDP_sequence_packet` defined many unused
fields. Replace this with per-message types that carry only the
required fields. Make these fields `const` where possible.
This loop is run once before the `if()` test, then again at the top of
both the true and false branches of the `if`. Remove the runs inside
the conditional, since they should produce the same result as the run
that occurs before the conditional.
- Use std::integral_constant instead of a static function that returns
the value
- Remove unused protocol_family
- Replace the enum with a typedef for the one type that the enum was
used to define