Local Wireless Technical Walkthrough
A technical deep dive into how Ryujinx became the first Switch emulator to implement “local wireless” multiplayer support!
This blog is a behind the scenes deep dive into the Local Wireless (LDN Service) implementation we've created for Ryujinx, currently in a pre-release stage. If you're just interested in using the build, you can find it over on our Patreon:
Introducing "Local Wireless" Multiplayer Support
This work is a combination of efforts from Ac_K and myself (riperiperi), and has been on our radar ever since Mario Kart 8 Deluxe got in-game. A few months ago, we were the first switch emulator to get system link multiplayer working in any form, though in a proof of concept branch that was never merged. This was achieved through that game's "LAN" mode though, which only a select few first party games support. You will find that "Local Wireless" is a lot more complicated, but at the same time much more enticing to implement, as many more games support it.
Why Local Wireless?
When you want to play games over the internet, you generally use that game's Online mode. So why not do that here?
The first option would be connecting directly to Nintendo's servers using information and user accounts dumped from your console. If you've been in the Switch modding community for a while, you already know what the problem with this is. Unlike the Wii U, official server communication is known to have a bunch of traps that can easily get your console banned from the service if we don't behave exactly like an unmodified switch. That isn't reasonable to expect right now, and we don't want to be responsible for bans, so that's out of the question.
The second option is emulating these official servers ourselves, implementing all of the matchmaking logic that NSO uses to bring players together, generally called NEX. However, not all games will use NEX, and even if they do, they may use some variation that requires a custom implementation/plugin for that specific game. This is also a bit of a legal minefield, given NSO's subscription fees and that it could be considered as "DRM".
Thankfully, there is a third option: Local Wireless. Local Wireless has been a staple of handheld game consoles since the DS first introduced it. All this really does is link nearby players together in the same wireless network - this is a regular IP network that you can use all your favourite transport protocols over. If a game has an online mode, it is very easy to port their netcode to work over a Local Wireless network instead. You can see this happening with most games on the Switch, with a few exceptions. (curse you, Garfield Kart!)
This way, we gain support for "online" multiplayer in many of the games with online modes, while avoiding any unwanted attention we might garner by re-implementing details of a live, paid service. History has proven this to be a potential legal liability, though it will obviously become more tempting when the console reaches End-of-Life, where we might want to preserve some of the online features that would otherwise be lost forever, whenever that time comes.
You can find a list of games that support local wireless here. It isn't a complete list, but it's a good indication of games that should work with our implementation. If they don't, they likely will eventually!
Implementation
Wireless networking in the switch is really simple. Games can host wireless networks that other games can discover and connect to, all by using the "LDN" service. The first step is always a player creating a network to host a room in the game. The most common approach is for each game to display nearby hosted networks in a list, and let other users pick one to join. These networks are "scanned" similar to wireless networks on a computer, but with a special set of filters unique to the Switch, such as Title ID and "Scene ID". While they only allow a small number of networks show up in these lists, the implementation beyond is generally a match for the game's online multiplayer. This allows us to get the same experience without connecting to official servers or making a replacement.
Our LDN implementation manages and routes players together in virtual networks on a central server, allowing players to connect to "local" wireless networks over the internet. Ryujinx connects to our server and can set up, scan for and join networks which are fully managed on our side to make them as easy to scan through as possible. Connecting to a network is only the first step, though. When a game is connected to a network, it will start using the BSD service to open sockets to other clients in the network, identified by IPs and MAC addresses provided by the LDN service. This is where our magic happens - BSD sockets created while connected to local wireless are proxied over the internet, to allow players to connect to each other from around the world!
The proxy performs all packet routing between clients of the virtual network. Connections between players are Peer-To-Peer by default (the proxy runs on the host), so long as their network supports NAT configuration with UPnP. This ensures the lowest latency possible between players in each game room. If this fails for whatever reason, or you manually disable P2P, you will still be able to host by proxying all traffic through our servers. If you can't host in the P2P mode, you can let someone else host for most games to avoid this.
Local multiplayer therefore works as if everyone playing with Ryujinx were in the same room, always within Wi-Fi range. You might imagine that this will make game lists become crowded, and that is true! But this is only the default mode - we strongly encourage users to generate and share a passphrase, which will allow them to enter a "private room" where they can only see games from people with the same passphrase, and vice versa. These games are not visible in public, and are useful if you want to join someone in game without random players showing up. They will also not show up on our public game list, but the number of private rooms and their players will still be visible.
You can find a list of all currently active games at https://ldn.ryujinx.org. Private games aren't shown, but the number of them is. You'll also be able to see the number of active games and players in the game list in Ryujinx itself, sourced from our JSON API at https://ldn.ryujinx.org/api/public_games.
Strength in Numbers
As I mentioned above, this has been a joint effort between me and Ac_K. This will be detailed fully in our PR for these changes, to come after all of this is tested and complete.
It wasn't known at the time, but the real start of all of this was back in March 2018, with Ac_K's initial implementation of the BSD service, and a few followup PRs to improve its functionality from fellow Ryujinx developers emmauss and Thog. With just this service, and some minor changes on top, we were able to get LAN play working in MK8D as described above. Having this service mostly complete and functional was a huge boon to starting work on Local Wireless.
From then on, Ac_K began work on reversing the service as found on the Switch, as we do with all our service implementations. Key parts of the service were reversed as early as May, though it quickly became obvious that we would need to handle IP routing in a special way to simulate a wireless network, even for local communication. Games use a lot of broadcast packets, and rely on each game instance having a unique IP to know who they came from, and that it wasn't ourselves. This wouldn't work when running multiple instances on one machine, which we might want to do when testing Ryujinx... Despite this, a simple server was crafted to handle network creation and discovery for LDN, a good first step.
After Resolution Scaling released, Ac_K and myself got back on it, where I helped work on the more networking oriented parts of the system. I reworked the Master Server, and fitted it with an all new Proxy system to help simulate a private wireless network. Now able to test games running with it, Ac_K accelerated work on more of the Service intricacies, data types and functionality. We've been back and forth on a lot of things - what needs to be done functionally, and how the real service behaves. This allowed for some rapid iteration, leading to the preview release you see today!
Testers Needed!
There are a few reasons that we're doing this with a separate build stream, compared to a PR:
There are a surprisingly large number of games with wireless networking support. We've only had the opportunity to test a small selection of these internally, so this experiment will let us test more games with more players in each room. This will stress both the implementation of LDN, the P2P proxy system and our own servers, giving us valuable metrics so we can make certain we provision a sufficient level of service.
We are also looking for games that connect using TCP, which will be signaled with an error in the log as it is untested. If you find a game that shows an error like this, please make sure to let us know on Discord so that it can be properly tested and fixed!
This special build (and all future updates) will ensure that all people are up to date as the networking implementation is developed, and that people have an easy way to find the build. There is potential for rapid change, so we will continue to distribute future builds on Patreon and notify on Discord when they change.
Thank You!
Thanks for reading this post! If you're interested in the implementation, give it a try and get back to us with your results. If you like what you see and would like to support us implementing more features, why not do so through our Patreon? You can find the link at the top of the page... actually, it's pretty far away so I'll just put it here too: