vaderag Posted November 1, 2022 Share Posted November 1, 2022 (edited) I'm re-setting up MAME using the default import in Launchbox... Before, I had a single key which saved and a different single key which loaded a save state to a slot, but I can't seem to find a way to do this... am I missing something Is there a way "quick save" and "quick load" without having to go through a dialogue... sure I had it set up before... Also I'm trying to get MAME rewind to work - in theory - if I Pause, and then press Shift-` ¬ then it will rewind. It tries to but it fails and says see error.log - there is a major problem with this... I cannot find an error.log file anywhere...! Can anyone advise how I can get MAME rewind to work? Thanks Edited November 1, 2022 by vaderag Quote Link to comment Share on other sites More sharing options...
JoeViking245 Posted November 1, 2022 Share Posted November 1, 2022 5 hours ago, vaderag said: Before, I had a single key which saved and a different single key which loaded a save state to a slot, but I can't seem to find a way to do this... am I missing something Is there a way "quick save" and "quick load" without having to go through a dialogue... sure I had it set up before... Have you changed the default key(s) in MAME for save and load? When you say "go through a dialog", are you talking about accessing the save/load feature available in the pause menu (Pause Screen)? If you go through the pause screen, LB is setup to use MAME's default F7 (Load) and Shift+F7 (Save). But sounds like you may have had (at one point?) set up different keys in MAME itself to a single key [respectively]. Which, regardless of how it's setup in the pause menu, would still work for you directly in MAME. Just not via the pause menu. 5 hours ago, vaderag said: I'm trying to get MAME rewind to work - in theory - if I Pause, and then press Shift-` ¬ then it will rewind. It tries to but it fails You may need (want?) to disable LB's pause menu. At least for MAME. I'm pretty sure that when you're in the pause screen, direct keystrokes are not sent to the emulator. If you want to disable it (at least do so for testing), edit your MAME emulator and in the Pause Screen section, un-check Enable Game Pause Screen. Quote Link to comment Share on other sites More sharing options...
vaderag Posted November 1, 2022 Author Share Posted November 1, 2022 8 minutes ago, JoeViking245 said: Have you changed the default key(s) in MAME for save and load? No and yes (as in I hadn't, but had in my previous setup which was not setup via LB). I've now tried it both ways in the new setup. Behaviour is the same, but when you save it asks for a slot. Previously it never asked for a slot so presumably I'd set it to default to a slot somehow. It may have been something I did with AHK, but... I don't remember! 10 minutes ago, JoeViking245 said: You may need (want?) to disable LB's pause menu. It's not actually on at the moment. My keys are being passed and step forward works, but I can't rewind... From a bit of research I'm now but convinced it can work well with Mame, but would like to know for sure! Quote Link to comment Share on other sites More sharing options...
JoeViking245 Posted November 1, 2022 Share Posted November 1, 2022 1 hour ago, vaderag said: Previously it never asked for a slot so presumably I'd set it to default to a slot somehow. It may have been something I did with AHK Having an AHK script to do that makes sense and is probably the only way. I don't think MAME has a setting-of-sorts for always using slot "1" (or whatever). 1 hour ago, vaderag said: My keys are being passed and step forward works, but I can't rewind Have you tried this during gameplay? Vs. pausing then 'rewinding'. May double check your key assignments in MAME. Honestly, I never paid attention that rewind was even a thing. I've used the Insert [key] for fast forwarding though. Quote Link to comment Share on other sites More sharing options...
vaderag Posted November 2, 2022 Author Share Posted November 2, 2022 (edited) 11 hours ago, JoeViking245 said: Having an AHK script to do that makes sense and is probably the only way. I don't think MAME has a setting-of-sorts for always using slot "1" (or whatever). Have you tried this during gameplay? Vs. pausing then 'rewinding'. May double check your key assignments in MAME. Honestly, I never paid attention that rewind was even a thing. I've used the Insert [key] for fast forwarding though. I'm giving up on the rewind - pretty certain that it's just a debugging feature However, I really need to get the save / reload working - I don't think it was a script because I'd have seen the window pop up quickly which I never did Perhaps it was an older version of mame thing... Seems someone else has it working here: How do you save a game state in MAME? (arcadecontrols.com) EDIT: I also don't recall re-compiling mame to do this, but this might be an alternate option - combine AHK with hiding the Load/Save dialogue as explained here: Solved - Need diff to disable load state messages (arcadecontrols.com) Edited November 2, 2022 by vaderag Quote Link to comment Share on other sites More sharing options...
JoeViking245 Posted November 2, 2022 Share Posted November 2, 2022 2 hours ago, vaderag said: I'm giving up on the rewind Good. 🙃 2 hours ago, vaderag said: Perhaps it was an older version of mame thing... Kind of doubt it. But it may have been something in a MAME offshoot.?.?.. MAMEui, qmc2, or something funky like that. To limit save/load to a single slot, I can see having both pros and cons (compared to having up to 10). Depends on the end-user's needs/requirements. I do know that you can have a specific game or system automatically load a specific save state by creating an ini file. In the ini folder create a text file like mslugx.ini (for Metal Slug X) or neogeo.ini (for all NeoGeo games) and put in just 1 line. "state 1". Every time you load that game or a game using that source, save state 1 will load automatically. 2 hours ago, vaderag said: Seems someone else has it working here If you reassign the save state to Shift+P, I imagine if you hold the P a little longer, you'd end up sending Shift+PPPPPPPPPP. Ultimately saving it in the "P" slot. lol Compiling your own as both links talked about, would be a pain. Though not really difficult. But still a pain. I think it'd be a lot easier to just have an AHK script and put it in the Running Script section of your MAME emulator. Chances are that it won't work if you want to upload your high scores to the Community Leaderboard. To make it work, you need to have "-keyboardprovider dinput" in the command line (which is put there by default). This example will load the save state in slot 1 (if one exists) for a game when you press "A". SetKeyDelay, 0, 50 a:: { send {F7} sleep 100 send 1 } Yes, you will still see a popup for a split second. Because of how MAME is, it's not a popup "window" you can hide. You could also change the "a" to "$F7" to have F7 load slot 1 (vs it just bringing up the option menu). If you wanted to get real crazy, you could probably create a lua script plugin to do this and have it work directly in MAME. With this, you wouldn't have to compile-your-own MAME anytime you update. Or ever, for that matter. Here's something you might be able to modify. If you're so inclined. It's set to save and load to the "auto" slot [only]. http://forum.arcadecontrols.com/index.php/topic,151810.msg1623419.html#msg1623419 Quote Link to comment Share on other sites More sharing options...
vaderag Posted November 2, 2022 Author Share Posted November 2, 2022 4 minutes ago, JoeViking245 said: Good. 🙃 Kind of doubt it. But it may have been something in a MAME offshoot.?.?.. MAMEui, qmc2, or something funky like that. To limit save/load to a single slot, I can see having both pros and cons (compared to having up to 10). Depends on the end-user's needs/requirements. I do know that you can have a specific game or system automatically load a specific save state by creating an ini file. In the ini folder create a text file like mslugx.ini (for Metal Slug X) or neogeo.ini (for all NeoGeo games) and put in just 1 line. "state 1". Every time you load that game or a game using that source, save state 1 will load automatically. If you reassign the save state to Shift+P, I imagine if you hold the P a little longer, you'd end up sending Shift+PPPPPPPPPP. Ultimately saving it in the "P" slot. lol Compiling your own as both links talked about, would be a pain. Though not really difficult. But still a pain. I think it'd be a lot easier to just have an AHK script and put it in the Running Script section of your MAME emulator. Chances are that it won't work if you want to upload your high scores to the Community Leaderboard. To make it work, you need to have "-keyboardprovider dinput" in the command line (which is put there by default). This example will load the save state in slot 1 (if one exists) for a game when you press "A". SetKeyDelay, 0, 50 a:: { send {F7} sleep 100 send 1 } Yes, you will still see a popup for a split second. Because of how MAME is, it's not a popup "window" you can hide. You could also change the "a" to "$F7" to have F7 load slot 1 (vs it just bringing up the option menu). If you wanted to get real crazy, you could probably create a lua script plugin to do this and have it work directly in MAME. With this, you wouldn't have to compile-your-own MAME anytime you update. Or ever, for that matter. Here's something you might be able to modify. If you're so inclined. It's set to save and load to the "auto" slot [only]. http://forum.arcadecontrols.com/index.php/topic,151810.msg1623419.html#msg1623419 Interesting... leaning towards the AHK option - will the running script be active while running - I understood it as 'at launch' but that's probably my misunderstanding! I have no idea what an lua script plugin is... but i might investigate! Quote Link to comment Share on other sites More sharing options...
JoeViking245 Posted November 2, 2022 Share Posted November 2, 2022 44 minutes ago, vaderag said: will the running script be active while running Yes. It's launched in conjunction with the game starting and stays active until either the script closes itself (ExitApp) or the game exits (then it's forced closed). 45 minutes ago, vaderag said: I have no idea what an lua script plugin is... but i might investigate! Scripting MAME via Lua — MAME Documentation 0.249 documentation (mamedev.org) MAME Lua Class Reference — MAME Documentation 0.249 documentation (mamedev.org) They're pretty cool and can do A LOT of things. I do pretty well with AHK, C# and batch files (which are actually lot more powerful than you can imagine). I can look at a Lua script and understand and follow through with what it's intending to do. But I'll be damned if I could write/create one from scratch. lol But it's been a couple years since I've looked at them. In the last year, MAME has updated their Lua scripting documentation. Namely in the Class Reference section. Though I haven't really looked at it. Maybe you'll have more patience than me. Quote Link to comment Share on other sites More sharing options...
vaderag Posted November 2, 2022 Author Share Posted November 2, 2022 (edited) 4 minutes ago, JoeViking245 said: Yes. It's launched in conjunction with the game starting and stays active until either the script closes itself (ExitApp) or the game exits (then it's forced closed). Scripting MAME via Lua — MAME Documentation 0.249 documentation (mamedev.org) MAME Lua Class Reference — MAME Documentation 0.249 documentation (mamedev.org) They're pretty cool and can do A LOT of things. I do pretty well with AHK, C# and batch files (which are actually lot more powerful than you can imagine). I can look at a Lua script and understand and follow through with what it's intending to do. But I'll be damned if I could write/create one from scratch. lol But it's been a couple years since I've looked at them. In the last year, MAME has updated their Lua scripting documentation. Namely in the Class Reference section. Though I haven't really looked at it. Maybe you'll have more patience than me. I've started down a rabbit hole now... if I hasn't seen that save script you sent i may not have done, but if i could just bind those actions to a keypress (rather than a menu) then I'll be golden! Struggling to find any reference in MAME to the emu.register_ options tho Edited November 2, 2022 by vaderag Quote Link to comment Share on other sites More sharing options...
JoeViking245 Posted November 2, 2022 Share Posted November 2, 2022 16 minutes ago, vaderag said: Struggling to find any reference in MAME to the emu.register_ options That might have been when I gave up. lol Time for a little deeper digging. It's "documented" in the luaengine.cpp file. mame/luaengine.cpp at master · mamedev/mame · GitHub In the commented section emu library and starting on line 603. Have fun. Quote Link to comment Share on other sites More sharing options...
vaderag Posted November 2, 2022 Author Share Posted November 2, 2022 (edited) 28 minutes ago, JoeViking245 said: That might have been when I gave up. lol Time for a little deeper digging. It's "documented" in the luaengine.cpp file. mame/luaengine.cpp at master · mamedev/mame · GitHub In the commented section emu library and starting on line 603. Have fun. My head is hurthing lol There is some code which I'm trying to parse already included - it seems that this somehow (and that somehow is the key) listens for a hotkey which when pressed does something... not really sure what, but that bit doesnt matter BUT, it's making my head hurt to reverse engineer!! All I need is... if [insertkey here] is pressed, then manager:machine():save("auto") EDIT: sorry - i though that would collapse! Oh well -- license:BSD-3-Clause -- copyright-holders:Vas Crabb local exports = { name = 'timecode', version = '0.0.1', description = 'Timecode recorder plugin', license = 'BSD-3-Clause', author = { name = 'Vas Crabb' } } local timecode = exports function timecode.startplugin() local file -- the timecode log file local write -- whether to record a timecode on the next emulated frame local text -- name of current part local frame_count -- emulated frame counter local start_frame -- start frame count for current part local start_time -- start time for current part local total_time -- total time of parts so far this session local count -- current timecode number local show_counter -- whether to show elapsed time since last timecode local show_total -- whether to show the total time of parts local frame_mode -- 0 to count frames, 1 to assume 60 Hz local hotkey_seq -- input sequence to record timecode local hotkey_pressed -- whether the hotkey was pressed on the last frame update local hotkey_cfg -- configuration string for the hotkey local item_framemode -- menu index of frame mode item local item_hotkey -- menu index of hotkey item local commonui -- common UI helpers local hotkey_poller -- helper for configuring hotkey local function get_settings_path() return emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/timecode' end local function set_default_hotkey() hotkey_seq = manager.machine.input:seq_from_tokens('KEYCODE_F12 NOT KEYCODE_LSHIFT NOT KEYCODE_RSHIFT NOT KEYCODE_LALT NOT KEYCODE_RALT') hotkey_cfg = nil end local function load_settings() -- set defaults frame_mode = 1 set_default_hotkey() -- try to open configuration file local cfgname = get_settings_path() .. '/plugin.cfg' local cfgfile = io.open(cfgname, 'r') if not cfgfile then return -- probably harmless, configuration just doesn't exist yet end -- parse settings as JSON local json = require('json') local settings = json.parse(cfgfile:read('a')) cfgfile:close() if not settings then emu.print_error(string.format('Error loading timecode recorder settings: error parsing file "%s" as JSON', cfgname)) return end -- recover frame mode local count_frames = settings.count_frames if count_frames ~= nil then frame_mode = count_frames and 0 or 1 end -- recover hotkey assignment hotkey_cfg = settings.hotkey if hotkey_cfg then local seq = manager.machine.input:seq_from_tokens(hotkey_cfg) if seq then hotkey_seq = seq end end end local function save_settings() local path = get_settings_path() local attr = lfs.attributes(path) if not attr then lfs.mkdir(path) elseif attr.mode ~= 'directory' then emu.print_error(string.format('Error saving timecode recorder settings: "%s" is not a directory', path)) return end local json = require('json') local settings = { count_frames = frame_mode == 0 } if hotkey_cfg then settings.hotkey = hotkey_cfg end local data = json.stringify(settings, { indent = true }) local cfgname = path .. '/plugin.cfg' local cfgfile = io.open(cfgname, 'w') if not cfgfile then emu.print_error(string.format('Error saving timecode recorder settings: error opening file "%s" for writing', cfgname)) return end cfgfile:write(data) cfgfile:close() end local function process_frame() if (not file) or manager.machine.paused then return end if write then write = false count = count + 1 show_total = true -- time from beginning of playback in milliseconds, HH:MM:SS.fff and frames local curtime = manager.machine.time local sec_start = curtime.seconds local msec_start = (sec_start * 1000) + curtime.msec local msec_start_str = string.format('%015d', msec_start) local curtime_str = string.format( '%02d:%02d:%02d.%03d', sec_start // (60 * 60), (sec_start // 60) % 60, sec_start % 60, msec_start % 1000) local frame_start_str = string.format('%015d', (frame_mode == 0) and frame_count or (msec_start * 60 // 1000)) -- elapsed from previous timecode in milliseconds, HH:MM:SS.fff and frames local elapsed = curtime - start_time local sec_elapsed = elapsed.seconds local msec_elapsed = (sec_elapsed * 1000) + elapsed.msec local msec_elapsed_str = string.format('%015d', msec_elapsed) local elapsed_str = string.format( '%02d:%02d:%02d.%03d', sec_elapsed // (60 * 60), (sec_elapsed // 60) % 60, sec_elapsed % 60, msec_elapsed % 1000) local frame_elapsed_str = string.format('%015d', (frame_mode == 0) and (frame_count - start_frame) or (msec_elapsed * 60 // 1000)) -- update start of part start_frame = frame_count start_time = curtime local message local key if count == 1 then text = 'INTRO' show_counter = true message = string.format(_p('plugin-timecode', 'TIMECODE: Intro started at %s'), curtime_str) key = 'INTRO_START' elseif count == 2 then total_time = total_time + elapsed show_counter = false message = string.format(_p('plugin-timecode', 'TIMECODE: Intro duration %s'), elapsed_str) key = 'INTRO_STOP' elseif count == 3 then text = 'GAMEPLAY' show_counter = true message = string.format(_p('plugin-timecode', 'TIMECODE: Gameplay started at %s'), curtime_str) key = 'GAMEPLAY_START' elseif count == 4 then total_time = total_time + elapsed show_counter = false message = string.format(_p('plugin-timecode', 'TIMECODE: Gameplay duration %s'), elapsed_str) key = 'GAMEPLAY_STOP' elseif (count % 2) == 1 then local extrano = (count - 3) // 2 text = string.format('EXTRA %d', extrano) show_counter = true message = string.format(_p('plugin-timecode', 'TIMECODE: Extra %d started at %s'), extrano, curtime_str) key = string.format('EXTRA_START_%03d', extrano) else local extrano = (count - 4) // 2 total_time = total_time + elapsed show_counter = false message = string.format(_p('plugin-timecode', 'TIMECODE: Extra %d duration %s'), extrano, elapsed_str) key = string.format('EXTRA_STOP_%03d', extrano) end emu.print_info(message) manager.machine:popmessage(message) file:write( string.format( '%-19s %s %s %s %s %s %s\n', key, curtime_str, elapsed_str, msec_start_str, msec_elapsed_str, frame_start_str, frame_elapsed_str)) end frame_count = frame_count + 1 end local function process_frame_done() local machine = manager.machine if show_counter then -- show duration of current part local counter = (machine.time - start_time).seconds local counter_str = string.format( machine.paused and _p('plugin-timecode', ' %s%s%02d:%02d [paused] ') or _p('plugin-timecode', ' %s%s%02d:%02d '), text, (#text > 0) and ' ' or '', (counter // 60) % 60, counter % 60) machine.render.ui_container:draw_text('right', 0, counter_str, 0xf0f01010, 0xff000000) end if show_total then -- show total time for all parts so far local total = ((show_counter and (machine.time - start_time) or emu.attotime()) + total_time).seconds total_str = string.format(_p('plugin-timecode', 'TOTAL %02d:%02d '), (total // 60) % 60, total % 60) machine.render.ui_container:draw_text('left', 0, total_str, 0xf010f010, 0xff000000) end if file then local pressed = machine.input:seq_pressed(hotkey_seq) if (not hotkey_pressed) and pressed then write = true end hotkey_pressed = pressed end end local function start() file = nil show_counter = false show_total = false load_settings() -- only do timecode recording if we're doing input recording local options = manager.machine.options.entries local filename = options.record:value() if #filename > 0 then filename = filename .. '.timecode' emu.print_info(string.format('Record input timecode file: %s', filename)) file = emu.file(options.input_directory:value(), 0x0e) -- FIXME: magic number for flags local openerr = file:open(filename) if openerr then -- TODO: this used to throw a fatal error and log the error description emu.print_error('Failed to open file for input timecode recording') file = nil else write = false text = '' frame_count = 0 start_frame = 0 start_time = emu.attotime() total_time = emu.attotime() count = 0 show_counter = false show_total = false hotkey_pressed = false file:write('# ==========================================\n') file:write('# TIMECODE FILE FOR VIDEO PREVIEW GENERATION\n') file:write('# ==========================================\n') file:write('#\n') file:write('# VIDEO_PART: code of video timecode\n') file:write('# START: start time (hh:mm:ss.mmm)\n') file:write('# ELAPSED: elapsed time (hh:mm:ss.mmm)\n') file:write('# MSEC_START: start time (milliseconds)\n') file:write('# MSEC_ELAPSED: elapsed time (milliseconds)\n') file:write('# FRAME_START: start time (frames)\n') file:write('# FRAME_ELAPSED: elapsed time (frames)\n') file:write('#\n') file:write('# VIDEO_PART======= START======= ELAPSED===== MSEC_START===== MSEC_ELAPSED=== FRAME_START==== FRAME_ELAPSED==\n') end end end local function stop() -- close the file if we're recording if file then file:close() file = nil end -- try to save settings save_settings() end local function menu_callback(index, event) if hotkey_poller then if hotkey_poller:poll() then if hotkey_poller.sequence then hotkey_seq = hotkey_poller.sequence hotkey_cfg = manager.machine.input:seq_to_tokens(hotkey_seq) end hotkey_poller = nil return true end elseif index == item_framemode then if (event == 'select') or (event == 'left') or (event == 'right') then frame_mode = (frame_mode ~= 0) and 0 or 1 return true end elseif index == item_hotkey then if event == 'select' then if not commonui then commonui = require('commonui') end hotkey_poller = commonui.switch_polling_helper() return true elseif event == 'clear' then set_default_hotkey() return true end end return false end local function menu_populate() local result = { } table.insert(result, { _p('plugin-timecode', 'Timecode Recorder'), '', 'off' }) table.insert(result, { '---', '', '' }) local frame_mode_val = (frame_mode > 0) and _p('plugin-timecode', 'Assume 60 Hz') or _p('plugins-timecode', 'Count emulated frames') table.insert(result, { _p('plugin-timecode', 'Frame numbers'), frame_mode_val, (frame_mode > 0) and 'l' or 'r' }) item_framemode = #result table.insert(result, { _p('plugin-timecode', 'Hotkey'), manager.machine.input:seq_name(hotkey_seq), hotkey_poller and 'lr' or '' }) item_hotkey = #result if hotkey_poller then return hotkey_poller:overlay(result) else return result end end emu.register_frame(process_frame) emu.register_frame_done(process_frame_done) emu.register_prestart(start) emu.register_stop(stop) emu.register_menu(menu_callback, menu_populate, _p('plugin-timecode', 'Timecode Recorder')) end return exports Edited November 2, 2022 by vaderag Quote Link to comment Share on other sites More sharing options...
JoeViking245 Posted November 2, 2022 Share Posted November 2, 2022 I think I remember for sure now why I stopped messing with it. And a sure reminder as to not go trying it again. lol You might have a little better luck with something like /MAME/plugins/autofire/init.lua 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.