Basically, I would like to see things standardized. Having to rewrite my function alias code for each emulator just so that I can keep myself sane isn't very fun and it is very annoying to work around certain limitations in one emulator that the other two don't suffer from.
So, here is a simple list of things I would like to see done at some point:
- Change EMULATORNAME.command() to "emu.command()". There's little sense in having 3 (4, 5, etc) variations on the same commands.
- Bump FCEUX up to use full 24-bit color like SNES9x and Gens. This will greatly increase the flexibility with Lua painting, remove the huge speed penalty for drawing (every non-named color is a speed hit because it has to look it up; this is especially noticable if you do a lot of pixel(x, y, "#FF0000") v. using "red").
- Standardize the box drawing commands to be like Gens, or at least like so:
-- gui.drawbox(x1, y1, x2, y2, outline, fill)
- Gens's method is a bit weird (fill first, then outline, so drawing a hollow box is slightly annoying) but superior to the other implementations that have no native filled-box capabilities.
- Provide a standard font set; possibly use the FCEUX one and Gens one (selectable) with colored outlines:
-- gui.text(x, y, text, color, outline, type)
- ...where type is 0 (small, Gens) or 1 (large, FCEUX). Obviously, the background highlighting on the FCEUX one would be changed to the Gens-style border.
- Make all the commands actually work the same. Does joypad.read read the user's input, the movie's input, or the input set by joypad.set? Choose one and make it a standard.
A lot of these will undoubtedly break a lot of scripts, but as it is it would make future development a lot less prone to having to keep 3 copies of the syntax open for each emulator you do work on, and would make scripts a lot easier to move to other consoles. (For example you could create a basic hitbox drawer that just took 4 memory addresses and drew them to the screen without having to modify the rest of the code).
I feel like the biggest problems are more the cases where you realize "oh, I can't do this at all in this emulator". Or cases where it's technically possible but won't work anywhere near as well. For example, savestates in Snes9x are more than 100 times slower than savestates in Gens for some reason, so a lot of scripts that would work well in Gens aren't really practical to run in Snes9x, and nothing can be done about it from the Lua side.
(Some numbers from my quick tests:
- Gens savestate save: 0.3 milliseconds
- Gens savestate load: 0.3 milliseconds
- Snes9x savestate save: 21.7 milliseconds
- Snes9x savestate load: 41.7 milliseconds)
Lack of "print" console functionality in non-Gens emulators is probably the most annoying and debilitating difference I've noticed so far, though. Having to debug with modal popup dialog boxes instead of real logging is painful. It's possible to work around that with enough effort but it's a big waste of time to accomplish something that Lua is supposed to have a working function for already. (And don't say that "print" is only supposed to go to stdout... Lua actually recommends replacing print with a version that instead goes to something like an application-specific console window.)
That's sensible. Although it's easy to get the same result by adding something like "emu = emu or gens or snes9x" at the top of every script, this would make for one less thing to worry about.
I'd call it 32-bit color, since 24-bit color would be missing the alpha component, and it's quite useful to have full alpha transparency control in the drawing functions. But that speed comparison you give is a bit weird. I guess FCEUX does some really inefficient color conversion for "#FF0000" to be noticeably slower than "red". Well, the fastest thing even with 32-bit color is to use numbers instead of strings, so for example 0xFF0000FF for 32-bit color red would be fastest since it avoids allocating any memory or going through string tables at all.
I think it's really bad when it's not able to read the movie's input, since then a script that works fine when you're recording will totally fail when you try to play back the same input since it's not getting the button presses anymore. So I'd say joypad.read should always get the same buttons the emulated game is getting (whether they come from the user or from movie playback), and things that need to know what buttons the user is trying to press even when the emulation is normally supposed to ignore that input should use a different function for that special purpose (that's what joypad.peek is for in Gens).
Sorry to pick on this particular example, but... 4 memory addresses? I think that having a "drawbox" function already covers most of the cross-game code reuse you could get out of hitbox drawing code, and that there's not much point attempting to generalize something that's so commonly vastly different from game to game, especially when going across platforms.
3 (fast). I'm the one that added the option to set the compression level, so I'm pretty sure there's no more speed to be gotten out of tweaking it from what I used. It used to be even slower before that option was added (was hardcoded to 6 IIRC).
EDIT: I tried 1 (fastest) and it wasn't measurably faster, and switching it to completely uncompressed made it noticeably slower.
EDIT2:
I think it's better to have the more important one first, and the fill is probably more important since it makes a bigger visual difference. And I don't think a totally hollow box is a sensible default, there should be at least some partially-opaque fill or else it's too easy to get your boxes confused or overlook them, especially for hitboxes. And gui.text has fill first, outline second, so this order is more consistent with that.
So, so damn true.
Also, I noticed that Gens can handle this, while FCEUX crashes.
saveme = savestate.create()
while memory.readwhatever ~= somevalue do
savestate.save(saveme)
emu.frameadvance()
end
savestate.load(saveme)
I'm guessing it has to do with how Gens handles the memory used for savestates.
Sage advice from a friend of Jim: So put your tinfoil hat back in the closet, open your eyes to the truth, and realize that the government is in fact causing austismal cancer with it's 9/11 fluoride vaccinations of your water supply.
You can create something similar with gui.text and a table, but yeah.
Yeah. What would actually be even better is to have "emu.version()" return {emulatorname, versionnumber}, allowing scripts to selectively change functions to handle arguments differently based on them. That way if you write a nice interface for emulator A, you don't have to rewrite all the functions for another one, and can instead just use the same module for all of them.
Xkeeper wrote:
- Bump FCEUX up to use full 24-bit color like SNES9x and Gens. This will greatly increase the flexibility with Lua painting, remove the huge speed penalty for drawing (every non-named color is a speed hit because it has to look it up; this is especially noticable if you do a lot of pixel(x, y, "#FF0000") v. using "red").
I'd call it 32-bit color, since 24-bit color would be missing the alpha component, and it's quite useful to have full alpha transparency control in the drawing functions. But that speed comparison you give is a bit weird. I guess FCEUX does some really inefficient color conversion for "#FF0000" to be noticeably slower than "red". Well, the fastest thing even with 32-bit color is to use numbers instead of strings, so for example 0xFF0000FF for 32-bit color red would be fastest since it avoids allocating any memory or going through string tables at all.[/quote]
I actually meant 32-bit, I guess; it's just 24-bit is what is actually drawn (8R8G8B). I'm just used to calling it 24-bit.
FCEUX's comparison is to run though every palette color and calculate how close it is to matching the color you gave (and the function to check picks some pretty bizarre ones). Combine this with some bizarre palette functionality (colors will randomly shift if you load/reload the same palette) and... yeah.
Results aren't cached (and doing so would be another performance hit, especially if you like using dynamic colors), so every single call to a drawing function has to look it up again.
Generally my system tops out at drawing about 2000~2500 individual pixels to the screen before it starts choking.
Xkeeper wrote:
- Make all the commands actually work the same. Does joypad.read read the user's input, the movie's input, or the input set by joypad.set? Choose one and make it a standard.
I think it's really bad when it's not able to read the movie's input, since then a script that works fine when you're recording will totally fail when you try to play back the same input since it's not getting the button presses anymore. So I'd say joypad.read should always get the same buttons the emulated game is getting (whether they come from the user or from movie playback), and things that need to know what buttons the user is trying to press even when the emulation is normally supposed to ignore that input should use a different function for that special purpose (that's what joypad.peek is for in Gens).
I wasn't saying that you shouldn't be able to check movie input at all! Just that it isn't consistant anywhere.
Xkeeper wrote:
(For example you could create a basic hitbox drawer that just took 4 memory addresses and drew them to the screen without having to modify the rest of the code).
Sorry to pick on this particular example, but... 4 memory addresses? I think that having a "drawbox" function already covers most of the cross-game code reuse you could get out of hitbox drawing code, and that there's not much point attempting to generalize something that's so commonly vastly different from game to game, especially when going across platforms.
The whole point was that it was just a simple example. Would you prefer something more like "takes two values representing X and Y speed and graphs them out as a scrolling linechart"?
Invalid Session. Please resubmit the form.
Joined: 2/12/2008
Posts: 67
Location: San Francisco Bay Area, CA
TheRandomPie_IV wrote:
Another small addition that would be nice is a function to load config files, as there doesn't seem to be a(n easy?) way to do this at the monent.
The "Lua way" to load config files is dofile(), which is part of the Lua standard library. Just write your config files in Lua and load them at runtime.
Emulator Coder, Site Developer, Site Owner, Expert player
(3574)
Joined: 11/3/2004
Posts: 4754
Location: Tennessee
I can't speak for the other emulators very well, but I can say in terms of lua implementation FCEUX falls short of GENS in just about everyway.
GENS lua implementation is work of art and what all lua should aspire to. I'd love to get FCEUX up to par, but I can't do it alone. Much of this is over my head and beyond my motivation (Lua isn't really my thing generally). If anyone was interested in helping, I'd be grateful.