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

Emulated local Wi-Fi multiplayer support (2 players max) #242

Merged
merged 24 commits into from
Dec 26, 2024

Conversation

BernardoGomesNegri
Copy link

@BernardoGomesNegri BernardoGomesNegri commented Dec 1, 2024

This patch adds support for emulated local (Wi-Fi) multiplayer using libretro's netpacket API, which allows a core to send and receive arbitrary data packets across the network. In RetroArch, this can be done by using the same interface used for netplay.
Unfortunately, due to the DS's tight latency requirements for local networks, it only works for good LAN connections on a few games. I managed to play Pokémon HeartGold between my phone (connected to a WiFi AP very close by) and my PC (wired), for example. On an emulated connection, the same game worked with 8ms ping and 3% packet loss, but it could get rather laggy at times.
Thanks to @JesseTG for helping me with this.

@BernardoGomesNegri BernardoGomesNegri changed the base branch from main to dev December 1, 2024 16:51
@JesseTG
Copy link
Owner

JesseTG commented Dec 1, 2024

Thanks for contributing! I'll review and test this and get back to you as soon as I can.

@JesseTG JesseTG self-requested a review December 1, 2024 16:55
@JesseTG JesseTG added the enhancement New feature or request label Dec 1, 2024
@BernardoGomesNegri
Copy link
Author

I seem to have made a bit of a mess when trying to rebase this to the dev branch. I Will try to fix it.

@BernardoGomesNegri
Copy link
Author

Would close issue #225

Copy link
Owner

@JesseTG JesseTG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution, and for your patience. Broadly speaking this looks okay, but there are some changes I'd like you to make. Some of the proposed changes will reduce the number of copies made of packets, which may help performance.

I also suggest adding Tracy markers at the start of important functions, then running a RelWithDebInfo build through Tracy.

Once you make these changes I'll take another review pass and test it. Keep up the good work!

src/libretro/core/core.hpp Outdated Show resolved Hide resolved
src/libretro/net/mp.hpp Outdated Show resolved Hide resolved
src/libretro/core/core.hpp Outdated Show resolved Hide resolved
src/libretro/net/mp.hpp Outdated Show resolved Hide resolved
src/libretro/environment.cpp Outdated Show resolved Hide resolved
src/libretro/libretro.cpp Outdated Show resolved Hide resolved
src/libretro/libretro.cpp Show resolved Hide resolved
src/libretro/libretro.cpp Outdated Show resolved Hide resolved
src/libretro/net/mp.hpp Outdated Show resolved Hide resolved
src/libretro/libretro.hpp Outdated Show resolved Hide resolved
@BernardoGomesNegri
Copy link
Author

Added the tracepoints, will run with Tracy and analyze the result later.

@BernardoGomesNegri
Copy link
Author

Ran it with Tracy, it appears that most of the time spent in the multiplayer code is spent waiting blocking for a packet. Sending a packet and receiving one are super quick by comparison.
The biggest improvements I can see are if waiting for a packet did not require busy-looping (which would improve battery usage on mobile devices) and if waiting for a packet could be done asynchronously from actually rendering and processing and everything else that has to be done in a frame.
The only room for improvement in melonDS DS that I see is tweaking the timeout. But even that has little effect: melonDS (or the game) will often call recv again after receiving a timeout.
Maybe improvements could also be made on RetroArch's implementation of netpacket? But I think this is very close to the best that can be done while only touching melonDS DS and with my rather limited knowledge of emulation and networking.

@BernardoGomesNegri
Copy link
Author

BernardoGomesNegri commented Dec 3, 2024

I've been trying to get Tracy to connect to my Android phone, but no luck so far. Any ideas?
Edit: fixed it.

@BernardoGomesNegri
Copy link
Author

After testing more, it seems timeout has little impact on performance. However, too low of a timeout will cause frequent crashes. The value of 25 ms is good.

@JesseTG
Copy link
Owner

JesseTG commented Dec 5, 2024

I'll test this today and get back to you with thoughts. I'll also compare this to the upstream implementation, see if there's something we can do about the blocking.

src/libretro/net/mp.cpp Outdated Show resolved Hide resolved
@JesseTG
Copy link
Owner

JesseTG commented Dec 5, 2024

I had a chance to reproduce the lag in the core you described. Notably, standalone melonDS does not have this issue.

Before we can merge this PR, we need to diagnose the lag and see how much of it actually comes from the core. I'll take some traces and get back to you.

@JesseTG
Copy link
Owner

JesseTG commented Dec 5, 2024

When you took your trace, what build settings did you use? I built the core (but not RetroArch itself) with optimizations and the lag wasn't as pronounced. I'm still looking over the trace for specifics.

@BernardoGomesNegri
Copy link
Author

The traces I took were taken in a RelWithDebInfo build.
The lag might be because right now this PR does not drop stale packets. I did not think it was needed because games often try to get incoming packets more than once per frame.

@JesseTG
Copy link
Owner

JesseTG commented Dec 6, 2024

I wonder if upstream melonDS does the same thing? I'll look into it.

@JesseTG
Copy link
Owner

JesseTG commented Dec 11, 2024

The lag is far less pronounced when building the core in RelWithDebInfo mode, and RetroArch in Release mode. (For both devices I'm testing with, too.)

Let me see what happens when using a wireless connection.

@JesseTG
Copy link
Owner

JesseTG commented Dec 11, 2024

Not too bad over wireless. It looks like on frames where retro_netpacket_poll_receive_t is most responsible for slowdown, it's because it's called more often. Or, rather, Platform::MP_RecvReplies is called more often -- and that leads to retro_netpacket_poll_receive_t being called more.

@JesseTG
Copy link
Owner

JesseTG commented Dec 11, 2024

I had a helpful conversation with @Arisotura on the melonDS Discord server about how the standalone frontend handles networking, starting here. If you're on Discord, what's your username? If not, I'll copy the discussion here.

@BernardoGomesNegri
Copy link
Author

I implemented dropping stale packets. However, it made it harder at the beginning of a connection (taking me four times in Mario Kart DS on Wi-Fi LAN) for little (maybe none) performance benefit.

@JesseTG
Copy link
Owner

JesseTG commented Dec 15, 2024

That little, huh? I'm starting to suspect that future optimizations may be needed in RetroArch itself. Especially because I just noticed that RetroArch doesn't actually implement RETRO_NETPACKET_UNRELIABLE, presumably because the author never got around to it -- so we're stuck with TCP for the time being.

We've established that LAN netplay works okay in the core, so I'd like to avoid spinning our wheels forever. With that in mind, I'd like you to revert 545871b, unless you happen to discover a benefit that outweighs the drawbacks.

Once you do that, I'll give your PR one more code review pass -- once outstanding feedback (if any) is addressed, I'll merge it and it'll be in the next release!

I'll also want to include a warning in the core that this will only work on a real LAN; players trying to use LAN netplay across the Internet is a common source of support requests, and I don't want to add to the deluge. I can do that before releasing 1.2.0, though.

@VGCCR
Copy link

VGCCR commented Dec 17, 2024

Can you test Dragon Quest IX with up to 4 players? This is the game that should be the most popular with Netplay.

@JesseTG
Copy link
Owner

JesseTG commented Dec 24, 2024

@BernardoGomesNegri Just checking in, seeing if you need anything. From our last conversation on Discord, I recall that this is what you were working on:

Well, there is the warning that it is for LAN only. But there are also some minor improvements such as keeping track of how many players are connected to reduce lag on the host when a client crashes, figuring out why the Android version (and only the Android version) crashes when hosting begins while content is loaded, rather than clicking "host" before starting the core, and testing >2 players.

I think first is keeping track of how many players there are, then testing >2 players, then figuring out a way to get crash reports on Android. I really don't want to have to download the Android emulator...

@BernardoGomesNegri
Copy link
Author

Currently fixing >2 players., having a few issues. Also haven't worked much on the problem lately.

@BernardoGomesNegri BernardoGomesNegri changed the title Emulated local Wi-Fi multiplayer support Emulated local Wi-Fi multiplayer support (2 players max) Dec 26, 2024
@BernardoGomesNegri
Copy link
Author

I think this is ready for a re-review. Right now, it only works for 2 players. Support for 3 players and more is only doable once MAC address randomization is done.

@JesseTG
Copy link
Owner

JesseTG commented Dec 26, 2024

Good to merge! There's some follow-up work that I'd like to occur before this makes it into the next release, but those can be done in separate PRs later. I'll open tickets with more details.

Thanks for your work!

@JesseTG JesseTG merged commit a3c57f0 into JesseTG:dev Dec 26, 2024
24 checks passed
@JesseTG JesseTG added the lan For issues related to LAN-based netplay. (No, VPNs won't work. It really has to be a LAN.) label Dec 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request lan For issues related to LAN-based netplay. (No, VPNs won't work. It really has to be a LAN.)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants