Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for netplay input delay. #819

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

joeldenning
Copy link
Contributor

@joeldenning joeldenning commented Jan 1, 2021

This is an improved version of #799. The primary goal of the change is to improve performance of netplay when using fixed input delay. By informing mupen64plus-core of the input delay, the client is able to be the source of truth for local player inputs instead of having to wait on the server for local inputs.

One thing to note about the implementation here - mupen core is still sending the original count to the server instead of the adjusted-for-input-delay count. This is perhaps something that could be changed later on, but I didn't want to change it now since it would have been a breaking change.

This change also could help with a future p2p implementation, as two player p2p relies on the client using local inputs without waiting on the network to enjoy the perf benefits of p2p.

I made this change as part of some work on m64p - here's the corresponding change there: https://github.com/m64p/mupen64plus-gui/pull/70/files

cc @loganmc10

@loganmc10
Copy link
Member

I'm not sure what performance is to be gained here. In order for the game to advance a frame, it needs the inputs from all players. So having the local player's inputs registered early isn't going to allow the game to advance any quicker.

The other potential issue is desyncs (unless I missed something). The local player never re-sends inputs, so if it registers "A" for frame 123, but that never arrives at the server, the server needs to make an assumption about what the input should be. The m64p server just copies the previous frame's inputs, but if that differs from what the local player registered, it will desync.

p2p is essentially a game where 1 of the players is hosting the server locally. In that case, the round trip time for that player's inputs would be <1ms, so I don't think there would be anything to be gained there either.

@joeldenning
Copy link
Contributor Author

joeldenning commented Jan 2, 2021

Thanks for your comments - am happy to discuss this over Discord, too, if that would help clarify. I believe this change does have performance benefits, and also would be needed for a p2p (and maybe rollback) implementation.

So having the local player's inputs registered early isn't going to allow the game to advance any quicker.

Inputs for a frame don't arrive in the same packet / udp datagram for all players, so it's possible for you to have all inputs for your opponents, but be waiting on the network for your own inputs.

if it registers "A" for frame 123, but that never arrives at the server, the server needs to make an assumption about what the input should be. The m64p server just copies the previous frame's inputs, but if that differs from what the local player registered, it will desync.

This is not true of m64p-netplay-server with fixed input delay. It never copies inputs for fixed input delay games, but rather it always waits for the client to send them.

p2p is essentially a game where 1 of the players is hosting the server locally. In that case, the round trip time for that player's inputs would be <1ms, so I don't think there would be anything to be gained there either.

With two player p2p, you can halve the input delay by not waiting on the host server to send your own inputs back to you, since it is unnecessary for the input to make a roundtrip. Instead, the inputs are traveling one-way in each direction. Consider the following example, where two players have a ping of 45ms to a server and also a ping of 45ms to each other.

Server

  1. For count 100, P1 and P2 send inputs to server. (45ms)
  2. Server receives inputs for both players and sends them to P1 (45ms)
  3. P1 netplay client updates PIF ram with inputs for P1 and P2, both of which came from the network.

Total Duration: 90ms

P2P

  1. For count 100, P1 and P2 send inputs directly to each other. (45ms).
  2. P1 netplay client receives P2 inputs. It does not receive inputs for itself (P1).
  3. P1 netplay client updates PIF ram, using P2's network inputs but P1's locally cached inputs.

Total Duration: 45ms

@loganmc10
Copy link
Member

Sorry yes I hadn't considered that neither player would need to receive their own packets in a p2p game. However it seems like that benefit would diminish with a 3rd and 4th player.

This is not true of m64p-netplay-server with fixed input delay. It never copies inputs for fixed input delay games, but rather it always waits for the client to send them

I don't think this is true currently, see:
https://github.com/m64p/m64p-netplay-server/blob/54f933dc599ede25b89997700e6daa419acaf3e5/udpServer.cpp#L230

The current core implementation has no method for retransmitting inputs. The server has no way to signal to the client "I never received inputs for frame 123, please resend". I think that would need to be implemented alongside this change (or before it).

Inputs for a frame don't arrive in the same packet / udp datagram for all players, so it's possible for you to have all inputs for your opponents, but be waiting on the network for your own inputs.

While this is true, the packets are being sent from the same source, and to the same destination, so any variance between arrival times for each player should be extremely minimal.

@joeldenning
Copy link
Contributor Author

Sorry yes I hadn't considered that neither player would need to receive their own packets in a p2p game. However it seems like that benefit would diminish with a 3rd and 4th player.

Agreed, 3+ players wouldn't be able to do this.

I don't think this is true currently, see:
https://github.com/m64p/m64p-netplay-server/blob/54f933dc599ede25b89997700e6daa419acaf3e5/udpServer.cpp#L230

The current core implementation has no method for retransmitting inputs. The server has no way to signal to the client "I never received inputs for frame 123, please resend". I think that would need to be implemented alongside this change (or before it).

Ah I didn't realize that was happening! Thanks for the link to the code - I see what's happening there. I agree that the "please retransmit" feature is needed to avoid desyncs, and am happy to spend some time on it. To implement that, the netplay client would need to store the previous inputs for a while before discarding them, which I don't think it currently does. Perhaps it should store 10ish frames of previous inputs in a linked list, in case the server asks for them?

@loganmc10
Copy link
Member

Perhaps it should store 10ish frames of previous inputs in a linked list, in case the server asks for them?

Choosing arbitrary values can be a little risky and could lead to instability (you never know how long somebody might hang/lose internet for). It would probably be better to just hold on to the input locally until it hears about that input from the server (once the server sends that input to the client, the client knows it's been received/registered with the server, thus there is no longer a need to retain it locally)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants