I always wanted to have a quick and user friendly net play experience, where I can just give a link to a friend so we can play a NES game together (without them having to have the same ROM, and download the emulator, and all that stuff).
After lots of browsing for NES web emulators, I came to the conclusion that jsnes is the more reliable one and the one that has better compatibility.
Also, its clean design allowed me to ignore every detail about the internals of the emulator (see the usage). I just receive the frame buffer and audio, then tell the emulator...
So to allow people play, the first idea was deploying a server and use WebSockets, but that would have been too expensive for a hobby project and it'd introduce latency problems since this kind of networking is latency-bound and not bandwidth-bound. The chosen technology was WebRTC, which allow peer to peer connection between browsers. Is not perfect though, real WebRTC applications such as Google Hangouts or other real time apps use TURN servers that act as a fallback mechanisms for cases when a true p2p connection is not possible. But, for simple network configurations, it worked fine.
Having the connection part done, and after thinking synchronization strategies for a while, the most reasonable one was starting instances of the emulator at the same time, using the host as the final source of truth and throwing the (very little) input lag to the guest. The host would send 2 byte per frame (1 bit per NES button per controller) and the guest would run one or two frames behind, without running its input until the host confirms it.
Other strategies were discarded since they may get out of sync, and the previous one seemed the only that was "unbreakable". This is based on the following premise (I don't know if it's true, but all my current code is based on it and so far it's working good): the only sources of randomness of the NES are the controllers' inputs at given frames. So if I have two browsers running the same emulator, with the same input for the two controllers, the games' random numbers will be equal on both sides and then both realities will stay in sync.
So here's the final result:
https://rodri042.github.io/nestation/
It's not feature complete (I want to add save states and a 'ROM history' section) but it's playable now.
I just wanted to share the experience and I hope this is useful for someone. The code is on GitHub too if you want to check it out.
---
Also, a question-
(*) Do you know if there are more emulator like jsnes, that don't have their cores and UI coupled. How is this design pattern called? I'd love to create similar web experiences for other platforms.
Thanks for reading!
After lots of browsing for NES web emulators, I came to the conclusion that jsnes is the more reliable one and the one that has better compatibility.
Also, its clean design allowed me to ignore every detail about the internals of the emulator (see the usage). I just receive the frame buffer and audio, then tell the emulator...
Code:
nes.frame()
...60 times per second with the inputs, and that's it! Magic! (*)So to allow people play, the first idea was deploying a server and use WebSockets, but that would have been too expensive for a hobby project and it'd introduce latency problems since this kind of networking is latency-bound and not bandwidth-bound. The chosen technology was WebRTC, which allow peer to peer connection between browsers. Is not perfect though, real WebRTC applications such as Google Hangouts or other real time apps use TURN servers that act as a fallback mechanisms for cases when a true p2p connection is not possible. But, for simple network configurations, it worked fine.
Having the connection part done, and after thinking synchronization strategies for a while, the most reasonable one was starting instances of the emulator at the same time, using the host as the final source of truth and throwing the (very little) input lag to the guest. The host would send 2 byte per frame (1 bit per NES button per controller) and the guest would run one or two frames behind, without running its input until the host confirms it.
Other strategies were discarded since they may get out of sync, and the previous one seemed the only that was "unbreakable". This is based on the following premise (I don't know if it's true, but all my current code is based on it and so far it's working good): the only sources of randomness of the NES are the controllers' inputs at given frames. So if I have two browsers running the same emulator, with the same input for the two controllers, the games' random numbers will be equal on both sides and then both realities will stay in sync.
So here's the final result:
https://rodri042.github.io/nestation/
It's not feature complete (I want to add save states and a 'ROM history' section) but it's playable now.
I just wanted to share the experience and I hope this is useful for someone. The code is on GitHub too if you want to check it out.
---
Also, a question-
(*) Do you know if there are more emulator like jsnes, that don't have their cores and UI coupled. How is this design pattern called? I'd love to create similar web experiences for other platforms.
Thanks for reading!