The netplay saga, ep 3
In the previous episode, I had basic input forwarding working, but we had problems due to the initial state being different on each side. So in this episode, I've been working on tackling this.

The first problem is the ROMs themselves. The first iteration of netplay required that each side have the same ROM, but this has the problem that there can be multiple revisions of the same game, and some games (hi Pokémon) even support multiplayer interaction with different games. Requiring every player to have the exact same ROM feels really restrictive, especially compared to a real-life DS multiplayer session, where each player has their own game cart (or doesn't, and uses download play).

Yet, we do need to ensure that every mirror client is using the exact same ROM as their mirror host. Two solutions: either having mirror hosts send their ROM to their mirror clients, or requiring all ROMs to already be present on all sides.

From an end user perspective, I don't like the second solution. It may require users to deal with complex multi-ROM setups, making sure they load everything in the right place; there's quite the potential for things to go wrong, or just for users to be confused.

So I went and experimented with the first solution. While it keeps things simple, it has the downside that transferring DS ROMs takes a while, due to their average size of 64MB. But there are ways to alleviate this: compressing the transferred data, but also skipping the transfer entirely if all sides already have the exact same ROM (which we can verify with a simple CRC).

Keep in mind that none of this is set in stone, and I'm largely experimenting here. We are still pretty far from a finished product.

Next step is ensuring that the emulator state on boot is the same on each side. For this, I had the idea of using the savestate system: basically, have the mirror host take a savestate after the ROM is loaded, send that state over to mirror clients, have them apply it, and it's guaranteed that all sides start with the exact same state.

I ran into a few issues with this. First, the savestate system doesn't save the BIOS and firmware, because it wasn't deemed necessary at the time I designed it. But right now, it's a requirement if we want our mirror clients to have the same user settings, MAC address, etc... as their mirror host. I also ran into a bug in the savestate system itself, which isn't a problem in most cases but turned out to be problematic in this current situation. After addressing all this, I was finally able to have all sides start from the exact same state. And it does fix the issues I had observed: games stay in perfect sync, items in Mario Kart will always pull the same item on each side, the AI players will stay in sync, etc...

This does have a bit of the same problem as sending ROMs around, though: melonDS savestates tend to be ~18MB in size. So, definitely, compression will come in handy here. I also want to look into other ways to optimize this: enet (the network library we use for this) isn't well suited for transferring large amounts of data like that, so it's slow.

But, overall, at this point we have something close to a viable netplay implementation. As I said, there's still a lot of work to turn this into a finished product, but so far it's looking pretty promising.

For one, the current savestate system uses files, which isn't ideal in this situation. We've had the idea of changing it to use memory buffers for a while, because the way it works (lots of small fread/fwrite calls) isn't ideal on some platforms (like the Switch). JesseTG is working on it, and this change will come in handy here, so I'm waiting for it. For the sake of testing, I circumvented this limitation in a pretty gross way, but... yeah.

Then there's a lot of UI work to be done. Integrating all this into the user interface properly, making things configurable instead of being hardcoded, making everything clear and intuitive, handling problematic situations gracefully... And, of course, I need to add support for headless melonDS instances, so other players can stay hidden from your view, replicating the true DS multiplayer experience.

There's also a bunch of performance testing and tuning to be done. During my testing, I observed some hiccups, but it's also worth noting that my computers are like a decade old, so they're not the best hardware around. I also haven't had the chance to test this over the internet, so I want to see how it performs in these situations.
kevincrans says:
Apr 11th 2023
This is harder than I thought.
I think it would be easier to get download play working (on host side, on client side slowdowns).
Alternatively, there is cloud-gaming (we're used to joycon drift now lol).
Just helping with ideas, it's good, I just think it's better if people can dump and provide their own rom.
Else melonds could as well send the rom over the network (maybe it's more legal if not stored to file).
Have good luck!
ari32 says:
Apr 13th 2023
I forget, what was the issue with pausing the emulator until the other players input comes again? Its just so much faster and more intuitive
jiin says:
Apr 15th 2023

Is local online play finally possible? I am so very excited!!!! Finally!!!
ThiccFurLizzy says:
May 12th 2023
As for compression, have you tried Zstandard? It should be fine licensing wise, and it's very fast while having a decent compression ratio. I haven't tested it with a savestate of the emulator, but it should perform ok.
ThiccFurLizzy says:
May 13th 2023
Ok, I actually tried compressing some savestates from 0.9.5 of various DS games, and with Compression Level 1 they got down from 18MB to 1.3MB
(I also tried up to level 19, but the gain was minimal, only down to around 1.1MB)
Considering the savestates would be from a bit after startup (most ram would be cleared) and are very similar in sections, maybe creating a dictionary with Zstd would make it even smaller and faster.

PokeFanHindi says:
Sep 10th 2023
hey im neew how to post faq
Agente9 says:
Sep 26th 2023
I had my Pokémon platinum game on my phone, I transferred the sav file to my laptop and downloaded a rom, when I started Melonds I chose the save file, I advanced in the adventure and when I close the emulator and open it again, I choose the game and It appears without a game and if I choose sav the saved progress does not appear and a new save file does not appear, what should I do so that when the game starts it is there?
Post a comment