This abstracts away the details of particular input devices for netplay,
and adds support for mice and (similar) lightguns. Unfortunately, in
practice, no core handles mice or lightguns in a savestate-safe way, so
they need to be used in stateless mode to be reliable, but they do work.
(1) All mode change code unified, so server mode changes and client mode
changes and announcements go through the same functions
(2) New messages which are translateable and work with multiple input
devices
The new input handling makes adding and removing players more
complicated, since data can be present that's not expected from the
connected clients list, or absent that's expected in the list but
actually shouldn't be there.
Netplay state demotions, i.e. changes from playing to spectating or
disconnected states, could cause chain disconnections of all other
clients. This was due to a bug in when MODE change messages were sent.
Clients rely on the server sending all messages in its own order, and as
a consequence, the server typically holds messages for retransmission
until they can be retransmitted at the correct time. MODE messages were
not held, so could be sent early. When they were sent early, this caused
other clients to panic and disconnect.
A smaller but much stupider secondary bug was also fixed, in which the
first connection could be dropped due simply to writing connections[0]
instead of connections[i] somewhere.
This commit adds support for temporary desync in netplay. When frontend
features that can't be truly synced, in particular rewind, are used,
netplay is momentarily disabled. As soon as the feature finished, e.g. a
rewind ending, netplay resumes with a state load. For rewind, netplay
peers won't actually experience the effect of rewind, but they will load
the rewound state.
This commit makes spectator mode and slave mode in netplay always stay
ahead of the input, thereby avoiding rewinds, which is sort of the
point. This also changes catch-up detection to be a bit less eager, so
that they hopefully don't flap between stalling for server input and
catching up with that input.
This patch transfers core_reset across netplay. Resets effectively
worked before thanks to check_frames, but this makes resets work even
without check_frames, and in particular should allow resets to force
sync in savestateless cores, bringing them one step closer to actually
being usable by non-experts.
Previously, if two clients were connected to the same server and one of
them was ahead of the server, the only way to rectify that situation was
for the client to get so far ahead that it stalled, as the server could
only catch up with an ahead client if all clients were ahead. That's
unrealistic. This gives the server the alternate option of demanding
that a client stall. This keeps things nicely in line even with >2
players.
Since the quirks protocol was that a core could report variable
savestate size, but the host then tells it "no", we should actually
accept the variable size quirk in netplay, since RetroArch refuses to
allow cores to actually produce variable-size states.
Previously, we could be stalled by one player but still reading data
from another, which would wedge the client because we would never act
upon the newly-read data. Now we act upon data even if we're stalled.
Fixes bugs in initial connection with high latency.
Making the netplay handshake protocol send the core and content as an
explicit command, so that the other side can (notionally) choose to load
it. That isn't implemented, of course.
The idea:
* Use a fixed number of delay_frames (eventually to be fixed at 120,
currently still uses the config variable, 0 will still be an option)
* Determine how long it takes to simulate a frame.
* Stall only if resimulating the intervening frames would be
sufficiently annoying (currently fixed at three frames worth of
time)
Because clients always try to catch up, the actual frame delay works out
automatically to be minimally zero and maximally the latency. If one
client is underpowered but the other is fine, the powerful one will
automatically take up the slack. Seems like the most reasonable system.
In resimulation mode, we only copy the buttons. The reason for this
is nonobvious:
If we resimulated nothing, then the /duration/ with which any input
was pressed would be approximately correct, since the original
simulation came in as the input came in, but the /number of times/
the input was pressed would be wrong, as there would be an
advancing wavefront of real data overtaking the simulated data
(which is really just real data offset by some frames).
That's acceptable for arrows in most situations, since the amount
you move is tied to the duration, but unacceptable for buttons,
which will seem to jerkily be pressed numerous times with those
wavefronts.
For the time being, if NAT traversal is successful it simply announces
it as an OSD message. In the future it will be used to inform a
matchmaking server of the public port.
This patch also included minor fixes to the NAT traversal implementation
to make the select it demands actually doable.
As well as the implementation magic, we now send a platform magic in our
connection header. If the core reports platform dependence and the
platform magic differs relevantly, the connection will be refused.
Since netplay_send_info (client handshake) and netplay_get_info (server
handshake) were practically identical, they've also been merged into a
single netplay_handshake.
This changes netplay host mode's behavior in net (normal) mode from
immediately blocking to waiting for a connection while allowing the game
to run, like spectator mode.
Spectate mode is now far more similar to net (normal) mode, and, more
importantly, it works. In addition, spectate mode will not fast-forward
to catch up with the server if it lags too far behind.
The receiving side of a player-flip request now does a forced rewind to
assure that any already-computed frames are computed with the players on
the right side.
Every frame (soon to be configurable), the server does a CRC-32 hash and
sends it to the client. If the client finds that its own hash is
different from the server's, it requests a fresh savestate.
This is a last-ditch effort to sync if all else fails, and it's a
best-effort situation. The size of the buffer should assure that we
always still have the frame around to CRC, but I imagine there are edge
cases where we don't. If you're in an edge case, the CRC is ignored.
Assuming the core supports saving/loading states, and (crucially)
assuming the states are portable across the architectures on both sides
of the connection, Netplay now supports the transmission of savestates.
Right now the frontend doesn't actually send any such requests, as it's
not clear exactly where the code for that should be.
This works in either direction, although I'll admit I have no idea what
happens if they both load at the same time.
Support for remote pausing, and with it, support for Netplay pausing the
frontend correctly. With this patch alone this doesn't work, since
there's no clean way for the frontend to tell Netplay that it's paused.