Post subject: Gens multi-game movies project
Joined: 10/20/2006
Posts: 1248
How can I make Gens believe I've presssed a key that I actually didn't press? I figured somebody here would know because movie playback wouldn't work without this. What I've done is disabled the Update_Input function by adding in a return at the beginning of the function itself. This made Gens not accept any of my input anymore. Then I've passed on some valid data to SetCurrentInputCondensed, but that didn't result in Gens thinking I've pressed a button. Any idea why it doesn't work? SetNextInputCondensed works, but I want the current input to be changed.
Emulator Coder, Skilled player (1310)
Joined: 12/21/2004
Posts: 2687
What exactly are you trying to do? Are you sure it can't be done more easily with a Lua script? Well, to answer your question directly even though it sounds like you're doing something weird, I think what you did didn't work because Update_Controllers runs right after the code you changed, and it calls SetCurrentInputCondensed which overwrites the effects of any calls you made to SetCurrentInputCondensed on the same frame, so you'd have to edit Update_Controllers instead of Update_Input to make it stick.
Joined: 10/20/2006
Posts: 1248
Thanks, that actually did the trick. ^^ Yes, I'm quite sure lua can't do it. That part with the input works like a charm now. :)
nitsuja wrote:
What exactly are you trying to do?
I guess this should be useful once it's done. Here's an extremely early test version. I just got it to work a view minutes ago, so I'm sure it's still buggy. My silly debug messages are still enabled. They cause the majority of the lag that's present in this version. Instructions: Make sure background input is disabled. No full screen. Close gens to safe settings. Open gens_multi_test.exe for X times. I recommend 2 times because it's least laggy. Load the same rom in each opened version of it. Play the game and the windows should remain perfectly in sync. The only game I've tested this with is Sonic 3 & Knuckles. Remains in sync for most of the time. It does desync at some certain points though. I'm not exactly sure why. This may be due to certain aspects of the emulation that I'm not aware of. Much more likely it's just some kind of ordinary bug in my code though. You can switch the windows while playing or switch to non-Gens-related windows and the games should stay in sync. If one appears to be frozen, then that's most likely just because Gens doesn't want to update the display of that window. Moving the window a bit to either side should fix it. This bug was already there before I messed with the code. The purpose of this project is to make creating multi-game movies a lot easier. In those cases you would of course load different games. Loading the same game, however, seems best to test how well the whole thing stays in sync. Movie recording most certainly won't work yet, as I have not tested it yet, nor ever thought of how it might influence the whole process yet. If it does work, then it's by coincidence. xD With re-recording I'm sure it doesn't work, as I only sync up gamepad input as of yet, so loading a state should only work for the currently focused window as of now. The whole thing is Windows-only. Link removed. :p Edit: I have checked the inputs in the cases I got a desync, but they were still perfectly the same for each frame. So, I now think the desyncs are caused by something that has to do with the emulation itself. The only difference in some of those cases were different amounts of lag frames, regardless of them having used the same input. Any ideas on how to fix this? Does input between two frames affect the RNG?
Emulator Coder, Skilled player (1310)
Joined: 12/21/2004
Posts: 2687
Kuwaga wrote:
Yes, I'm quite sure lua can't do it.
Actually, it all sounds doable in Lua to me from what you've described. I'm not 100% sure about the "more easily" part, though.
Kuwaga wrote:
Edit: I have checked the inputs in the cases I got a desync, but they were still perfectly the same for each frame. So, I now think the desyncs are caused by something that has to do with the emulation itself. The only difference in some of those cases were different amounts of lag frames, regardless of them having used the same input. Any ideas on how to fix this? Does input between two frames affect the RNG?
I think it'll hard to be sure what's going on until you have it working with re-recording. I still suspect that, if they had been recording to different movie files, a binary comparison between the movie files would show some difference in the cases that desynced. (It's been quite a while since I've seen Gens ever desync on its own like that, even with massive savestate use.) Input changing in-between frames could screw things up, but if you're only setting the input at the normal time then that shouldn't be happening.
Joined: 10/20/2006
Posts: 1248
Can lua handle mutexes and memory mapped files? That would make it more powerful than I had thought. I can't imagine this working at all without mutexes or mapped events. (I only use mutexes atm, which might be inefficient, but atm my primary goal is to get it to work at all) No, I'm quite sure the movie files would be the same. Written frames by the program in lead and read frames by the second one were the same for every frame in one of the cases that desynced right at the start. I'm quite sure there must be something else going on. Edit: Actually you're right, the movie files could still be different if writing to the movie file happens at another point throughout the frame than the point were I sync up the input. Because the input could have changed in between for one instance of the program. I'm beginning to understand, I hope. Input between frames could be the cause as I've written all of my code assuming it wouldn't matter. Writing the input to the memory mapped file happens at the same time throughout a frame as reading it. But the input is updated in between for the one that's writing. (I didn't think it would matter) I'll try a few ideas to fix it later today. Edit 2: Yep, input in between frames caused the problem. Fixed it now and haven't gotten a single desync yet. I also fixed a bug where you'd get a freeze sometimes when having more than 2 Gens synced up and then switching to a random window. I like how this is progressing. Edit 3: Guess what, movie recording already works. I've opened the same game 3 times and successfully recorded a .gmv that didn't desync upon playback. Then I've opened 3 different games and recorded me playing them at the same time in real time and the resulting movie didn't desync. ^^ Also, without those debug messages there's absolutely no lag visible. Unfortunately without savestates this is still pretty useless atm.
Emulator Coder, Skilled player (1310)
Joined: 12/21/2004
Posts: 2687
Kuwaga wrote:
Can lua handle mutexes and memory mapped files? That would make it more powerful than I had thought. I can't imagine this working at all without mutexes or mapped events. (I only use mutexes atm, which might be inefficient, but atm my primary goal is to get it to work at all)
It has a basic "fopen" style interface in its very minimal default library, which actually should be enough for this (I'm not saying it would be pretty or as fast as could be), but it's also easy to call C code from Lua, so you could either find or make a DLL that wraps mutexes or sockets or whatever and call functions from that, or you could make a small edit to the Gens source that defines a few short functions for those, then do the rest in Lua. I'm not recommending doing this particular thing in it especially since you're so far along already without it, just asserting that it's certainly possible.
Joined: 10/20/2006
Posts: 1248
Ah, I see. Anyway, I've now got save states, frame skip, slow mode, pausing, etc synced up. Frame advance doesn't work yet though for some reason. Do you know if pressing the frame advance button does not send a window message like most (if not all) of the other function keys?
upthorn
He/Him
Emulator Coder, Active player (392)
Joined: 3/24/2006
Posts: 1802
Kuwaga wrote:
Ah, I see. Anyway, I've now got save states, frame skip, slow mode, pausing, etc synced up. Frame advance doesn't work yet though for some reason. Do you know if pressing the frame advance button does not send a window message like most (if not all) of the other function keys?
That is correct. Frame advancing doesn't utilize a window message. Neither does the fast forward key. The reason for this is because it has to be continuous if the key remains held down, and hotkeyed window messages are only sent on first press.
How fleeting are all human passions compared with the massive continuity of ducks.
Joined: 10/20/2006
Posts: 1248
I see, that makes sense.
Emulator Coder, Skilled player (1310)
Joined: 12/21/2004
Posts: 2687
upthorn wrote:
That is correct. Frame advancing doesn't utilize a window message. Neither does the fast forward key. The reason for this is because it has to be continuous if the key remains held down, and hotkeyed window messages are only sent on first press.
Well, actually Windows does key repeat for those which are the reason some of the the very first implementations of frame advance in emulators had the continuous advance functionality... I think the actual reason is that now it's possible to assign hotkeys to things that aren't even keys such as mouse clicks or joypad button presses (basically any checks that have to go through DirectInput and bypass Window messages), and we wanted consistent repeat behavior even for those things, at least in the case of frame advance. That, and it's nice to be able to control the key repeat separately from the system global key repeat, since it doesn't make that much sense for your system key repeat setting to affect TASing advance speed. EDIT: I would think it'd be better to not try to synchronize things like which hotkeys are being pressed, and instead only synchronize the movie file and the current frame count. With the exception of saving and loading savestates, which has to be synchronized more directly.
Joined: 10/20/2006
Posts: 1248
nitsuja wrote:
EDIT: I would think it'd be better to not try to synchronize things like which hotkeys are being pressed, and instead only synchronize the movie file and the current frame count. With the exception of saving and loading savestates, which has to be synchronized more directly.
I think I'll sync up all save state related functionality and speed related functionality. The only thing that's left to implement in that regard is fast-forward and frame-advance. And I still have some spare bits for those anyway. I currently sync the emulators up by letting the faster ones do an active wait, so it'd unnecessarily consume processing power if I don't sync up speed related functionality. Also, if I set one to a faster frame skip than the other ones, the faster one would always have to wait for the slower one. I can still change my code to not use active waiting, but I'm not sure if it'd be worth the effort atm. The whole thing runs pretty smoothly now, even at high frame skips. You are basically suggesting that the emulator in lead mustn't change, don't you? So you could always take its speed and let its slaves advance at its pace. I want the user to be able to switch between the windows at any time. That would still work if the emulator in lead is set to background input, but only accepts input if one of the other Gens has the focus currently. I hadn't thought of that approach. I've currently implemented it in a way that the window in focus is always the leader and when there's no Gens window in focus the fastest one at advancing the previous frame takes the lead for the current frame. However, using a constant leader, if I switch to a different window and change the speed there using the menu instead of hotkeys, it wouldn't affect the emulator in lead. So I'd have to send it a message anyway. But without having the need to really sync anything up. Hm, I'd probably give that approach that I think you have suggested the upper hand. I'm wondering if I should rewrite my code. Hm, I think I'll finish it first as it is, then once it's done I'm going to think about if it's worth changing it. Or, I could keep my changing leader concept, and still do the background input thing. That way I could always let the fastest one be in lead for the current frame (as I had it initially intended to work out anyway). Should be the fastest option overall. Any form of active wait would definately have to disappear though.