Link to video
Full details in the description. It's not done yet (or close), but if nothing else the concept seems sound.
Also, for fuck's sake, can we get rid of the YOUR SIGNATURE HAS IMAGES nag yet? Put it in the fucking profile editing field and get rid of huge retarded signatures, don't nag me every fucking time I go to post because I have a mind-blowing 512 pixels of images in my signature.
The comments in the code are even worse. Lots of self-depreciation in it, since I made a lot of really dumb mistakes (including spending about an hour debugging a packet issue when it was really the repeater server sending strlen(strlen($buf)) of $buf (as in, a lot less than it should have).
Case in point, here's a snip:
-- netplay.start
-- sets up sockets, the connections, and other things
-- that will be relied on later for smooth sailing
-- settings table is currently just 'host'
-- but will later allow the delay, what players to use, etc.
-- Actually, this may be moved to an 'init' function,
-- with "start" setting up the game, configuring the delay, and
-- other stuff -- allowing runtime configuration of
-- controller values and other crap
function netplay.start(mode, settings)
if mode == "server" then
-- TODO: EVERYTHING. FUCK.
elseif mode == "client" then
-- todo: make the configuration configurable
-- one way or another
sockets['game'] = socket.udp();
bindname = "*" -- YOU
bindport = 7845 -- ALSO YOU
peername = settings['host'];
peerport = 7845
-- in retrospect, the 'settings' table
-- is kind of pointless, figure out something
-- better to do with it later
sockets['game']:setsockname(bindname, bindport)
sockets['game']:setpeername(peername, peerport);
sockets['game']:settimeout(0);
-- Some set up for who is what in this
-- Right now hard coding to always be player 1
-- What player I am
netplay.state['plocal'] = 1;
-- What the other player is
netplay.state['premote'] = 2;
-- Ideally setting these to 0 would
-- disable it entirely
-- but that takes EFFORT.
joypad.buffers[1] = {}; -- Player 1
joypad.buffers[2] = {}; -- Player 2
netplay.state['started'] = false;
netplay.state['delay'] = 6;
netplay.state['frame'] = 0;
-- Delay should be auto-configured based
-- on some timing
-- but that's MORE EFFORT.
-- besides, 10 should be obvious and
-- annoying as all hell
-- Should probably be moved to a dedicated wait loop somewhere
-- SO that we can keep sending it every second or so until we get a reply
netplay.send("start", nil);
end;
return true; -- why not
end;
Xkeeper....Here is a copy and paste of *part* of a reply I posted in the ZSNES forums yesterday:
Suffice to say Xkeeper, that after reading your description in that Youtube video, I am very excited to see what you will be able to accomplish with this project!
Netplay for old school emulation is simply not getting enough love in the emu community. Why anyone would frown upon the idea is beyond me. We need to get together and show the fighting game fans that it's not only about netplay to compete with each other, it's about the enjoyment that spectating brings. GGPO is gaining popularity by the day. But GGPO focuses on fighting games mainly, and things like live spectating is just a side benefit. I want to see a netplay client where the focus is "game broadcasting". And being able to watch someone play live and WITHIN the emulator...but for consoles rather than arcade.
Here's to seeing where this idea goes :)
The biggest issue with something like that is "dynamically joining". If you join 30 minutes into someone's game session, how will it cope with that? You would have to transfer a state to the client.
Now think of several people joining... uh oh, now we have a ton of data to send (each state is quite large) and we probably don't want to count on the client sending this data every time.
One thing might be to have "regular" savestates (say, every 60 seconds or so) and keep an input buffer of that time, so that a client can get the latest, then fast forward up to the newest point.
This is all theoretical and highly depends on savestates being able to be read as binary data, as well as being portable. It's a nice pipe dream, but who knows if it is possible?
Netplay for old school emulation is simply not getting enough love in the emu community. Why anyone would frown upon the idea is beyond me. We need to get together and show the fighting game fans that it's not only about netplay to compete with each other, it's about the enjoyment that spectating brings. GGPO is gaining popularity by the day. But GGPO focuses on fighting games mainly, and things like live spectating is just a side benefit. I want to see a netplay client where the focus is "game broadcasting". And being able to watch someone play live and WITHIN the emulator...but for consoles rather than arcade.
Here's to seeing where this idea goes :)
I have a vested interest in it, because even as I'm typing this post, I'm watching someone play Final Fantasy 7 over ePSXe's (bad) netplay system, occasionally cracking jokes and talking about stuff. I do this with friends all the time; ZSNES is a favorite of mine, and we've beaten Breath of Fire 3, Tales of Destiny (a 2P game, no less) and a bunch of other stuff.
I want to see what I can do, but no guarantees. I'm, unfortunately, very very ... sporadic, and often can't really focus on one thing. Just look at the date between the cross-emulator test (the basic implementation) and this.
Hitting the bug in FCEUX -- and other emulator-specific oddities, really -- doesn't help much at all.
Patashu wrote:
How are you going to cope with latency?
The current plan is to have input buffered for all players by x frames, where x is a number appropriate for the network latency. My test used 6 and got a smooth framerate, for example. (When the buffer runs empty, the script goes into a loop waiting for more).
So, you push A on frame 1; the delay is 10, so the core saves your input in the joypad buffer for frame #11, and sends it to the client and marks it as being for that frame, as well.
This works in reverse, so the other player also has the same input delay.
It is theoretically possible to run it delay-free for one player, but at the same time the second player would experience twice the delay.
"Broadcast" games, where there is only one player repeating its input elsewhere, will be lag-free. (It wouldn't make much sense to delay it for nothing!)
As it is, the plan is to send one frame per packet, providing for a fairly steady stream of input, and no stupid input tricks like tripling your input or other crap. One keyframe every 5 frames my ass.
This is all preliminary, and still open to a lot of shaping. The test right now is just very basic and doesn't do much (if it fails to get a response the first time, it doesn't even bother retrying). Just a proof of concept.
I didn't want to build it up too much, but at the same time, the concept of an external netplay client that works in several emulators is too exciting for me to pass up.
You know, to that end, one interesting idea I had a night or two ago, making a special feature for VBA that would allow it to mess with the link cable. The problem is that the real cable doesn't have latency (much) and I'm not sure how well it would work. And that depends on several things being there in VBA, too.
We'll see.
For spectating, it seems reasonable to me that you could have a central server handling all of the connecting and data passing stuff. Players would connect to the server and say "Hey, I'm playing X game on my computer", then as they play they'd stream input and periodic savestates to the server as you suggested. Then spectators could connect to the server and say "Hey, I have these games on my computer; who's playing what?" and when they see game X, they could click on it and get the latest savestate and access to the input stream.
This avoids the player having to worry about his upstream bandwidth or any issues with mass joins/disconnects; all that load gets transferred to the server instead.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
For spectating, it seems reasonable to me that you could have a central server handling all of the connecting and data passing stuff. Players would connect to the server and say "Hey, I'm playing X game on my computer", then as they play they'd stream input and periodic savestates to the server as you suggested. Then spectators could connect to the server and say "Hey, I have these games on my computer; who's playing what?" and when they see game X, they could click on it and get the latest savestate and access to the input stream.
This avoids the player having to worry about his upstream bandwidth or any issues with mass joins/disconnects; all that load gets transferred to the server instead.
I like this idea very much. Perhaps this is how Ponder does it with ggpo.
This is a post I just made regarding a discussion similar to this one over at the zsnes forums:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
GIL and Paulguy, thanks for the explanation and clarification guys, it's appreciated.
I have been exploring both Ustream and JustinTV for the past few hours or so, and here are my thoughts:
Both programs/websites are very innovative introductions into the world of spectating people play games. The whole concept is nothing short of SUPERB! The execution, well, not quite as spectacular.
Main problem is, after watching the way a lot of people set up their upstream broadcast methods, I think it's painfully obvious why spectating people play snes games via input emulation can't come soon enough. Out of the many streams I've visited, only a handful were of quality I'd label as exceptional.
A lot of them were quite choppy and some of these people even stream via camcorder off their TV sets :lol: I am not trying to bash the streamers....not at all. The less than stellar output quality boils down to the nature of the internet and how live streaming works. I fully get that. That is precisely the reason why I love GGPO so much. GGPO is the ideal application for spectating games IMHO. If only Ponder(GGPO author/admin) would spread his wings and add a little diversity to the program instead of focusing solely on fighting games, it would so much better.
If Grinvader and the remaining ZSNES crew, or xkeeper over at TASV, can fullfill their goal of implementing some sort of spectating feature, then I'm confident we will have a good chance of bringing over a large part of the UStream/JustinTV crowd and adapting them to this method of spectating snes games. This is something I will DEFINITELY work hard at once the feature is in place.
In the meantime, let's hope more people who currently stream at UStream/JustinTV will attempt to improve their streaming setup by using emulators as the video capture source, rather than their TV and a handycam, as well as not running their mouths and talking over the game's audio every 5 seconds, which is another annoyance I've noticed :lol:
Netplay is certainly nifty to have, but I want you to try a different project, a broadcasting system. It's simply a request, but one I hope is an intermediate step on the way to full netplay. One-way data transfer might be easier to handle than two-way.
We still might have a problem with things like SRAM or converting savestates around. Maybe tell the client user to start a new movie, from power-on, clear SRAM, and just send the entire movie's worth of input over.
The best case would be if one can broadcast a TASing session. The server doesn't send state saves/loads, just tells the client to produce the appropriate saves. After all, if the input matches, both server and client should be able to produce the same states. Low bandwidth usage would be nice.
If you're going to use FCEUX as a starting base, use emu.registerbefore for a function involving joypad.get on the server side, and "boundary" for joypad.set on the client side. That should avoid any nasty problems with input coming a frame late, particularly since we have multiple emulators running and we can tell them to delay as much as we want until the next frame is sent.
While I like to say I'm decent at using lua scripts, I haven't dealt with networking. I might want to see if I can at some point. Would love to help, but I'm not sure where to start.