From e6588480c477a8132676abbbb32bfc42287d8c6d Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Wed, 23 Mar 2022 20:27:30 +1100 Subject: [PATCH] Lua engine improvements (#9453) Made auto-boot script errors and plugin bootstrap errors fatal. Run auto-boot scripts in a sandbox. Globals can be accessed, but not set. The sandbox is cleared on hard reset, but not on soft reset. Added (hopefully) useful to string metafunctions to device_t and address space that show short names and tags. Fixed issues in plugins that surface when strict type checking is enabled, as this means numbers and nil are not automatically converted to strings. Plugins should be tested with debug builds to check for this. Made save item read_block raise an error on invalid arguments rather than returning an empty string, and made it use luaL_buffer directly rather than using the helper wrapper. Changed some more function bindings to use set_function to avoid issues related to ThePhD/sol2#608, and got rid of some unnecessary lambda captures. --- plugins/autofire/autofire_menu.lua | 4 +- plugins/cheatfind/init.lua | 10 +- plugins/inputmacro/inputmacro_menu.lua | 24 +-- plugins/timer/init.lua | 2 +- src/frontend/mame/luaengine.cpp | 275 +++++++++++++------------ src/frontend/mame/luaengine.h | 35 +++- src/frontend/mame/luaengine.ipp | 60 +++--- src/frontend/mame/luaengine_debug.cpp | 20 +- src/frontend/mame/luaengine_mem.cpp | 232 +++++++++++---------- src/frontend/mame/mame.cpp | 72 ++++++- src/frontend/mame/mame.h | 25 ++- 11 files changed, 417 insertions(+), 342 deletions(-) diff --git a/plugins/autofire/autofire_menu.lua b/plugins/autofire/autofire_menu.lua index 5c87e27a63d..e2287ce2276 100644 --- a/plugins/autofire/autofire_menu.lua +++ b/plugins/autofire/autofire_menu.lua @@ -157,8 +157,8 @@ local function populate_configure_menu(menu) configure_selection_save = #menu end table.insert(menu, {_p('plugin-autofire', 'Hotkey'), key_name, hotkey_poller and 'lr' or ''}) - table.insert(menu, {_p('plugin-autofire', 'On frames'), current_button.on_frames, current_button.on_frames > 1 and 'lr' or 'r'}) - table.insert(menu, {_p('plugin-autofire', 'Off frames'), current_button.off_frames, current_button.off_frames > 1 and 'lr' or 'r'}) + table.insert(menu, {_p('plugin-autofire', 'On frames'), tostring(current_button.on_frames), current_button.on_frames > 1 and 'lr' or 'r'}) + table.insert(menu, {_p('plugin-autofire', 'Off frames'), tostring(current_button.off_frames), current_button.off_frames > 1 and 'lr' or 'r'}) configure_menu_active = true end diff --git a/plugins/cheatfind/init.lua b/plugins/cheatfind/init.lua index d565b31437f..96617e12fb6 100644 --- a/plugins/cheatfind/init.lua +++ b/plugins/cheatfind/init.lua @@ -351,7 +351,7 @@ function cheatfind.startplugin() for num, func in ipairs(menu) do local item, f = func() if item then - menu_list[#menu_list + 1] = item + table.insert(menu_list, item) menu_func[#menu_list] = f end end @@ -715,9 +715,9 @@ function cheatfind.startplugin() end local m if optable[opsel] == "ltv" or optable[opsel] == "gtv" or optable[opsel] == "eqv" or optable[opsel] == "nev" then - m = { _("Value"), value, "" } + m = { _("Value"), tostring(value), "" } else - m = { _("Difference"), value, "" } + m = { _("Difference"), tostring(value), "" } end local max = 100 -- max value? menu_lim(value, 0, max, m) @@ -792,7 +792,7 @@ function cheatfind.startplugin() end menu[#menu + 1] = function() return { "---", "", "off" }, nil end menu[#menu + 1] = function() - local m = { _("Match block"), matchsel, "" } + local m = { _("Match block"), tostring(matchsel), "" } menu_lim(matchsel, 0, #matches[#matches], m) if matchsel == 0 then m[2] = _("All") @@ -1017,7 +1017,7 @@ function cheatfind.startplugin() end if matches[#matches].count > 100 then menu[#menu + 1] = function() - local m = { _("Page"), matchpg, "on" } + local m = { _("Page"), tostring(matchpg), "on" } local max if matchsel == 0 then max = math.ceil(matches[#matches].count / 100) - 1 diff --git a/plugins/inputmacro/inputmacro_menu.lua b/plugins/inputmacro/inputmacro_menu.lua index 33223e9f20f..0c22de4a8f6 100644 --- a/plugins/inputmacro/inputmacro_menu.lua +++ b/plugins/inputmacro/inputmacro_menu.lua @@ -347,7 +347,7 @@ local function add_edit_items(items) local input = manager.machine.input local arrows - items[#items + 1] = { _p('plugin-inputmacro', 'Name'), edit_name_buffer and (edit_name_buffer .. '_') or edit_current_macro.name, '' } + table.insert(items, { _p('plugin-inputmacro', 'Name'), edit_name_buffer and (edit_name_buffer .. '_') or edit_current_macro.name, '' }) edit_items[#items] = { action = 'name' } if not (edit_start_selection or edit_start_step or edit_menu_active) then edit_start_selection = #items @@ -356,11 +356,11 @@ local function add_edit_items(items) local binding = edit_current_macro.binding local activation = binding and input:seq_name(binding) or _p('plugin-inputmacro', '[not set]') - items[#items + 1] = { _p('plugin-inputmacro', 'Activation sequence'), activation, edit_switch_poller and 'lr' or '' } + table.insert(items, { _p('plugin-inputmacro', 'Activation sequence'), activation, edit_switch_poller and 'lr' or '' }) edit_items[#items] = { action = 'binding' } local releaseaction = edit_current_macro.earlycancel and _p('plugin-inputmacro', 'Stop immediately') or _p('plugin-inputmacro', 'Complete macro') - items[#items + 1] = { _p('plugin-inputmacro', 'On release'), releaseaction, edit_current_macro.earlycancel and 'r' or 'l' } + table.insert(items, { _p('plugin-inputmacro', 'On release'), releaseaction, edit_current_macro.earlycancel and 'r' or 'l' }) edit_items[#items] = { action = 'releaseaction' } local holdaction @@ -376,18 +376,18 @@ local function add_edit_items(items) else holdaction = string.format(_p('plugin-inputmacro', 'Prolong step %d'), #edit_current_macro.steps) end - items[#items + 1] = { _p('plugin-inputmacro', 'When held'), holdaction, arrows } + table.insert(items, { _p('plugin-inputmacro', 'When held'), holdaction, arrows }) edit_items[#items] = { action = 'holdaction' } for i, step in ipairs(edit_current_macro.steps) do - items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Step %d'), i), '', 'heading' } - items[#items + 1] = { _p('plugin-inputmacro', 'Delay (frames)'), step.delay, (step.delay > 0) and 'lr' or 'r' } + table.insert(items, { string.format(_p('plugin-inputmacro', 'Step %d'), i), '', 'heading' }) + table.insert(items, { _p('plugin-inputmacro', 'Delay (frames)'), tostring(step.delay), (step.delay > 0) and 'lr' or 'r' }) edit_items[#items] = { action = 'delay', step = i } if edit_start_step == i then edit_start_selection = #items end - items[#items + 1] = { _p('plugin-inputmacro', 'Duration (frames)'), step.duration, (step.duration > 1) and 'lr' or 'r' } + table.insert(items, { _p('plugin-inputmacro', 'Duration (frames)'), tostring(step.duration), (step.duration > 1) and 'lr' or 'r' }) edit_items[#items] = { action = 'duration', step = i } for j, input in ipairs(step.inputs) do @@ -399,17 +399,17 @@ local function add_edit_items(items) else inputname = _p('plugin-inputmacro', '[not set]') end - items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Input %d'), j), inputname, '' } + table.insert(items, { string.format(_p('plugin-inputmacro', 'Input %d'), j), inputname, '' }) edit_items[#items] = { action = 'input', step = i, input = j } end if step.inputs[#step.inputs].field then - items[#items + 1] = { _p('plugin-inputmacro', 'Add input'), '', '' } + table.insert(items, { _p('plugin-inputmacro', 'Add input'), '', '' }) edit_items[#items] = { action = 'addinput', step = i } end if #edit_current_macro.steps > 1 then - items[#items + 1] = { _p('plugin-inputmacro', 'Delete step'), '', '' } + table.insert(items, { _p('plugin-inputmacro', 'Delete step'), '', '' }) edit_items[#items] = { action = 'deletestep', step = i } end end @@ -417,7 +417,7 @@ local function add_edit_items(items) local laststep = edit_current_macro.steps[#edit_current_macro.steps] if laststep.inputs[#laststep.inputs].field then - items[#items + 1] = { '---', '', '' } + table.insert(items, { '---', '', '' }) arrows = 'lr' if edit_insert_position > #edit_current_macro.steps then @@ -425,7 +425,7 @@ local function add_edit_items(items) elseif edit_insert_position < 2 then arrows = 'r' end - items[#items + 1] = { _p('plugin-inputmacro', 'Add step at position'), edit_insert_position, arrows } + table.insert(items, { _p('plugin-inputmacro', 'Add step at position'), tostring(edit_insert_position), arrows }) edit_items[#items] = { action = 'addstep', step = i } end end diff --git a/plugins/timer/init.lua b/plugins/timer/init.lua index e7d7155b4c1..35dbb6431ac 100644 --- a/plugins/timer/init.lua +++ b/plugins/timer/init.lua @@ -38,7 +38,7 @@ function timer.startplugin() { '---', '', '' }, { _p("plugin-timer", "Current time"), sectohms(time), "off" }, { _p("plugin-timer", "Total time"), sectohms(total), "off" }, - { _p("plugin-timer", "Play Count"), play_count, "off" } }, + { _p("plugin-timer", "Play Count"), tostring(play_count), "off" } }, highlight, "idle" end diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 6981ebfe41b..db35b227faa 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -352,16 +352,18 @@ sol::object lua_engine::call_plugin(const std::string &name, sol::object in) { std::string field = "cb_" + name; sol::object obj = sol().registry()[field]; - if(obj.is()) + if (obj.is()) { auto res = invoke(obj.as(), in); - if(!res.valid()) + if (!res.valid()) { sol::error err = res; osd_printf_error("[LUA ERROR] in call_plugin: %s\n", err.what()); } else + { return res.get(); + } } return sol::lua_nil; } @@ -380,7 +382,7 @@ std::optional lua_engine::menu_populate(const std::string &menu, std::vect } else { - std::tuple, std::string> table = res; + std::tuple, std::optional > table = res; for (auto &entry : std::get<0>(table)) { if (entry.second.is()) @@ -389,7 +391,10 @@ std::optional lua_engine::menu_populate(const std::string &menu, std::vect menu_list.emplace_back(enttable.get(1, 2, 3)); } } - flags = std::get<2>(table); + if (std::get<2>(table)) + flags = *std::get<2>(table); + else + flags.clear(); return std::get<1>(table); } } @@ -400,7 +405,7 @@ std::optional lua_engine::menu_populate(const std::string &menu, std::vect std::pair > lua_engine::menu_callback(const std::string &menu, int index, const std::string &event) { std::string field = "menu_cb_" + menu; - std::pair > ret(false, std::nullopt); + std::pair, std::optional > ret(false, std::nullopt); sol::object obj = sol().registry()[field]; if (obj.is()) { @@ -415,7 +420,7 @@ std::pair > lua_engine::menu_callback(const std::strin ret = res; } } - return ret; + return std::make_pair(std::get<0>(ret) && *std::get<0>(ret), std::get<1>(ret)); } void lua_engine::set_machine(running_machine *machine) @@ -423,9 +428,10 @@ void lua_engine::set_machine(running_machine *machine) m_machine = machine; } -int lua_engine::enumerate_functions(const char *id, std::function &&callback) +template +size_t lua_engine::enumerate_functions(const char *id, T &&callback) { - int count = 0; + size_t count = 0; sol::object functable = sol().registry()[id]; if (functable.is()) { @@ -439,23 +445,24 @@ int lua_engine::enumerate_functions(const char *id, std::function 0; } @@ -521,21 +528,23 @@ void lua_engine::on_periodic() bool lua_engine::on_missing_mandatory_image(const std::string &instance_name) { bool handled = false; - enumerate_functions("LUA_ON_MANDATORY_FILE_MANAGER_OVERRIDE", [this, &instance_name, &handled](const sol::protected_function &func) - { - auto ret = invoke(func, instance_name); + enumerate_functions( + "LUA_ON_MANDATORY_FILE_MANAGER_OVERRIDE", + [&instance_name, &handled] (const sol::protected_function &func) + { + auto ret = invoke(func, instance_name); - if(!ret.valid()) - { - sol::error err = ret; - osd_printf_error("[LUA ERROR] in on_missing_mandatory_image: %s\n", err.what()); - } - else if (ret.get()) - { - handled = true; - } - return !handled; - }); + if (!ret.valid()) + { + sol::error err = ret; + osd_printf_error("[LUA ERROR] in on_missing_mandatory_image: %s\n", err.what()); + } + else if (ret.get()) + { + handled = true; + } + return !handled; + }); return handled; } @@ -829,7 +838,7 @@ void lua_engine::initialize() auto space = buf.prepare(len); space.add(file.read(space.get(), len)); buf.push(); - return sol::stack::pop(s); + return sol::make_reference(s, sol::stack_reference(s, -1)); }); file_type.set("write", [](emu_file &file, const std::string &data) { return file.write(data.data(), data.size()); }); file_type.set("puts", &emu_file::puts); @@ -974,12 +983,14 @@ void lua_engine::initialize() })); item_type.set("size", sol::readonly(&save_item::size)); item_type.set("count", sol::readonly(&save_item::count)); - item_type.set("read", [this](save_item &item, int offset) -> sol::object { - if(!item.base || (offset >= item.count)) + item_type.set("read", + [this] (save_item &item, int offset) -> sol::object + { + if (!item.base || (offset >= item.count)) return sol::lua_nil; const void *const data = reinterpret_cast(item.base) + (item.stride * (offset / item.valcount)); uint64_t ret = 0; - switch(item.size) + switch (item.size) { case 1: default: @@ -997,33 +1008,38 @@ void lua_engine::initialize() } return sol::make_object(sol(), ret); }); - item_type.set("read_block", [](save_item &item, sol::this_state s, int offset, size_t len) { - buffer_helper buf(s); - auto space = buf.prepare(len); - if(!item.base || ((offset + len) > (item.size * item.count))) + item_type.set("read_block", + [] (save_item &item, sol::this_state s, uint32_t offset, size_t len) -> sol::object + { + if (!item.base) { - space.add(0); + luaL_error(s, "Invalid save item"); + return sol::lua_nil; } - else + + if ((offset + len) > (item.size * item.count)) { - const uint32_t blocksize = item.size * item.valcount; - size_t remaining = len; - uint8_t *dest = reinterpret_cast(space.get()); - while(remaining) - { - const uint32_t blockno = offset / blocksize; - const uint32_t available = blocksize - (offset % blocksize); - const uint32_t chunk = (available < remaining) ? available : remaining; - const void *const source = reinterpret_cast(item.base) + (blockno * item.stride) + (offset % blocksize); - std::memcpy(dest, source, chunk); - offset += chunk; - remaining -= chunk; - dest += chunk; - } - space.add(len); + luaL_error(s, "Range extends beyond end of save item"); + return sol::lua_nil; } - buf.push(); - return sol::stack::pop(s); + + luaL_Buffer buff; + uint8_t *dest = reinterpret_cast(luaL_buffinitsize(s, &buff, len)); + const uint32_t blocksize = item.size * item.valcount; + size_t remaining = len; + while (remaining) + { + const uint32_t blockno = offset / blocksize; + const uint32_t available = blocksize - (offset % blocksize); + const uint32_t chunk = (available < remaining) ? available : remaining; + const void *const source = reinterpret_cast(item.base) + (blockno * item.stride) + (offset % blocksize); + std::memcpy(dest, source, chunk); + offset += chunk; + remaining -= chunk; + dest += chunk; + } + luaL_pushresultsize(&buff, len); + return sol::make_reference(s, sol::stack_reference(s, -1)); }); item_type.set("write", [](save_item &item, int offset, uint64_t value) { if(!item.base || (offset >= item.count)) @@ -1187,54 +1203,54 @@ void lua_engine::initialize() auto machine_type = sol().registry().new_usertype("machine", sol::no_constructor); - machine_type["exit"] = &running_machine::schedule_exit; - machine_type["hard_reset"] = &running_machine::schedule_hard_reset; - machine_type["soft_reset"] = &running_machine::schedule_soft_reset; - machine_type["save"] = &running_machine::schedule_save; // TODO: some kind of completion notification? - machine_type["load"] = &running_machine::schedule_load; // TODO: some kind of completion notification? - machine_type["buffer_save"] = - [] (running_machine &m, sol::this_state s) - { - // FIXME: this needs to schedule saving to a buffer and return asynchronously somehow - // right now it's broken by anonymous timers, synchronize, etc. - lua_State *L = s; - luaL_Buffer buff; - int size = ram_state::get_size(m.save()); - u8 *ptr = (u8 *)luaL_buffinitsize(L, &buff, size); - save_error error = m.save().write_buffer(ptr, size); - if (error == STATERR_NONE) + machine_type.set_function("exit", &running_machine::schedule_exit); + machine_type.set_function("hard_reset", &running_machine::schedule_hard_reset); + machine_type.set_function("soft_reset", &running_machine::schedule_soft_reset); + machine_type.set_function("save", &running_machine::schedule_save); // TODO: some kind of completion notification? + machine_type.set_function("load", &running_machine::schedule_load); // TODO: some kind of completion notification? + machine_type.set_function("buffer_save", + [] (running_machine &m, sol::this_state s) { - luaL_pushresultsize(&buff, size); - return sol::make_reference(L, sol::stack_reference(L, -1)); - } - luaL_error(L, "State save error."); - return sol::make_reference(L, nullptr); - }; - machine_type["buffer_load"] = - [] (running_machine &m, sol::this_state s, std::string str) - { - // FIXME: this needs to schedule loading from the buffer and return asynchronously somehow - // right now it's broken by anonymous timers, synchronize, etc. - save_error error = m.save().read_buffer((u8 *)str.data(), str.size()); - if (error == STATERR_NONE) + // FIXME: this needs to schedule saving to a buffer and return asynchronously somehow + // right now it's broken by anonymous timers, synchronize, etc. + lua_State *L = s; + luaL_Buffer buff; + int size = ram_state::get_size(m.save()); + u8 *ptr = (u8 *)luaL_buffinitsize(L, &buff, size); + save_error error = m.save().write_buffer(ptr, size); + if (error == STATERR_NONE) + { + luaL_pushresultsize(&buff, size); + return sol::make_reference(L, sol::stack_reference(L, -1)); + } + luaL_error(L, "State save error."); + return sol::make_reference(L, nullptr); + }); + machine_type.set_function("buffer_load", + [] (running_machine &m, sol::this_state s, std::string str) { - return true; - } - else + // FIXME: this needs to schedule loading from the buffer and return asynchronously somehow + // right now it's broken by anonymous timers, synchronize, etc. + save_error error = m.save().read_buffer((u8 *)str.data(), str.size()); + if (error == STATERR_NONE) + { + return true; + } + else + { + luaL_error(s,"State load error."); + return false; + } + }); + machine_type.set_function("popmessage", + [] (running_machine &m, std::optional str) { - luaL_error(s,"State load error."); - return false; - } - }; - machine_type["popmessage"] = - [] (running_machine &m, const char *str) - { - if (str) - m.popmessage("%s", str); - else - m.popmessage(); - }; - machine_type["logerror"] = [] (running_machine &m, std::string const *str) { m.logerror("[luaengine] %s\n", str); }; + if (str) + m.popmessage("%s", *str); + else + m.popmessage(); + }); + machine_type.set_function("logerror", [] (running_machine &m, char const *str) { m.logerror("[luaengine] %s\n", str); }); machine_type["time"] = sol::property(&running_machine::time); machine_type["system"] = sol::property(&running_machine::system); machine_type["parameters"] = sol::property(&running_machine::parameters); @@ -1337,15 +1353,16 @@ void lua_engine::initialize() auto device_type = sol().registry().new_usertype("device", sol::no_constructor); - device_type["subtag"] = &device_t::subtag; - device_type["siblingtag"] = &device_t::siblingtag; - device_type["memregion"] = &device_t::memregion; - device_type["memshare"] = &device_t::memshare; - device_type["membank"] = &device_t::membank; - device_type["ioport"] = &device_t::ioport; - device_type["subdevice"] = static_cast(&device_t::subdevice); - device_type["siblingdevice"] = static_cast(&device_t::siblingdevice); - device_type["parameter"] = &device_t::parameter; + device_type.set_function(sol::meta_function::to_string, [] (device_t &d) { return util::string_format("%s(%s)", d.shortname(), d.tag()); }); + device_type.set_function("subtag", &device_t::subtag); + device_type.set_function("siblingtag", &device_t::siblingtag); + device_type.set_function("memregion", &device_t::memregion); + device_type.set_function("memshare", &device_t::memshare); + device_type.set_function("membank", &device_t::membank); + device_type.set_function("ioport", &device_t::ioport); + device_type.set_function("subdevice", static_cast(&device_t::subdevice)); + device_type.set_function("siblingdevice", static_cast(&device_t::siblingdevice)); + device_type.set_function("parameter", &device_t::parameter); device_type["tag"] = sol::property(&device_t::tag); device_type["basetag"] = sol::property(&device_t::basetag); device_type["name"] = sol::property(&device_t::name); @@ -1914,35 +1931,29 @@ void lua_engine::resume(int nparam) luaL_unref(m_lua_state, LUA_REGISTRYINDEX, nparam); } -void lua_engine::run(sol::load_result res) +//------------------------------------------------- +// load_script - load script from file path +//------------------------------------------------- + +sol::load_result lua_engine::load_script(std::string const &filename) { - if(res.valid()) - { - auto ret = invoke(res.get()); - if(!ret.valid()) - { - sol::error err = ret; - osd_printf_error("[LUA ERROR] in run: %s\n", err.what()); - } - } - else - osd_printf_error("[LUA ERROR] %d loading Lua script\n", (int)res.status()); + return sol().load_file(filename); } //------------------------------------------------- -// execute - load and execute script +// load_string - load script from string //------------------------------------------------- -void lua_engine::load_script(const char *filename) +sol::load_result lua_engine::load_string(std::string const &value) { - run(sol().load_file(filename)); + return sol().load(value); } //------------------------------------------------- -// execute_string - execute script from string +// make_environment - make a sandbox //------------------------------------------------- -void lua_engine::load_string(const char *value) +sol::environment lua_engine::make_environment() { - run(sol().load(value)); + return sol::environment(sol(), sol::create, sol().globals()); } diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index 6c5f572885d..27761eb85b5 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -34,7 +34,6 @@ class lua_engine { public: // helper structures - class buffer_helper; template struct devenum; template struct simple_list_wrapper; template struct tag_object_ptr_map; @@ -48,8 +47,9 @@ public: ~lua_engine(); void initialize(); - void load_script(const char *filename); - void load_string(const char *value); + sol::load_result load_script(std::string const &filename); + sol::load_result load_string(std::string const &value); + sol::environment make_environment(); bool frame_hook(); @@ -122,9 +122,27 @@ public: sol::state_view &sol() const { return *m_sol_state; } -private: - template class enum_parser; + template + static std::decay_t > invoke(Func &&func, Params&&... args) + { + g_profiler.start(PROFILER_LUA); + try + { + auto result = func(std::forward(args)...); + g_profiler.stop(); + return result; + } + catch (...) + { + g_profiler.stop(); + throw; + } + } +private: + template class enum_parser; + + class buffer_helper; struct addr_space; class tap_helper; class addr_space_change_notif; @@ -170,17 +188,12 @@ private: void resume(int nparam); void register_function(sol::function func, const char *id); - int enumerate_functions(const char *id, std::function &&callback); + template size_t enumerate_functions(const char *id, T &&callback); bool execute_function(const char *id); sol::object call_plugin(const std::string &name, sol::object in); void close(); - void run(sol::load_result res); - - template - sol::protected_function_result invoke(TFunc &&func, TArgs&&... args); - void initialize_debug(sol::table &emu); void initialize_input(sol::table &emu); void initialize_memory(sol::table &emu); diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp index 0dd6d3d8d90..08d55a48e37 100644 --- a/src/frontend/mame/luaengine.ipp +++ b/src/frontend/mame/luaengine.ipp @@ -21,6 +21,24 @@ +template +struct lua_engine::simple_list_wrapper +{ + simple_list_wrapper(simple_list const &l) : list(l) { } + + simple_list const &list; +}; + + +template +struct lua_engine::tag_object_ptr_map +{ + tag_object_ptr_map(T const &m) : map(m) { } + + T const ↦ +}; + + class lua_engine::buffer_helper { private: @@ -110,24 +128,6 @@ public: }; -template -struct lua_engine::simple_list_wrapper -{ - simple_list_wrapper(simple_list const &l) : list(l) { } - - simple_list const &list; -}; - - -template -struct lua_engine::tag_object_ptr_map -{ - tag_object_ptr_map(T const &m) : map(m) { } - - T const ↦ -}; - - namespace sol { // don't convert core_options to a table directly @@ -491,13 +491,13 @@ struct lua_engine::addr_space }; -template +template class lua_engine::enum_parser { public: constexpr enum_parser(std::initializer_list > values) { - if (values.size() != SIZE) + if (values.size() != Size) throw false && "size template argument incorrectly specified"; std::copy(values.begin(), values.end(), m_map.begin()); } @@ -514,7 +514,7 @@ public: } private: - std::array, SIZE> m_map; + std::array, Size> m_map; }; @@ -527,7 +527,7 @@ template auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate &&), D &&dflt, const char *name, const char *desc) { return - [this, setter, dflt, name, desc] (T &self, sol::object cb) + [setter, dflt, name, desc] (T &self, sol::object cb) { if (cb == sol::lua_nil) { @@ -536,7 +536,7 @@ auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate && else if (cb.is()) { (self.*setter)(delegate( - [this, dflt, desc, cbfunc = cb.as()] () -> R + [dflt, desc, cbfunc = cb.as()] () -> R { if constexpr (std::is_same_v) { @@ -566,18 +566,4 @@ auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate && }; } - -//------------------------------------------------- -// invoke - invokes a function, wrapping profiler -//------------------------------------------------- - -template -inline sol::protected_function_result lua_engine::invoke(TFunc &&func, TArgs &&... args) -{ - g_profiler.start(PROFILER_LUA); - sol::protected_function_result result = func(std::forward(args)...); - g_profiler.stop(); - return result; -} - #endif // MAME_FRONTEND_MAME_LUAENGINE_IPP diff --git a/src/frontend/mame/luaengine_debug.cpp b/src/frontend/mame/luaengine_debug.cpp index 94748d5a897..e2c6713ff44 100644 --- a/src/frontend/mame/luaengine_debug.cpp +++ b/src/frontend/mame/luaengine_debug.cpp @@ -181,14 +181,14 @@ void lua_engine::initialize_debug(sol::table &emu) { "m", EXPSPACE_REGION } }; - auto const do_add_symbol = [this] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, std::optional setter, std::optional format) -> symbol_entry & + auto const do_add_symbol = [] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, std::optional setter, std::optional format) -> symbol_entry & { symbol_table::setter_func setfun; if (setter) - setfun = [this, cbfunc = std::move(*setter)] (u64 value) { invoke(cbfunc, value); }; + setfun = [cbfunc = std::move(*setter)] (u64 value) { invoke(cbfunc, value); }; return st.table().add( name, - [this, cbfunc = std::move(getter)] () -> u64 + [cbfunc = std::move(getter)] () -> u64 { auto result = invoke(cbfunc).get >(); if (result) @@ -217,12 +217,12 @@ void lua_engine::initialize_debug(sol::table &emu) [] (device_t &device) { return std::make_shared(device.machine(), nullptr, &device); })); symbol_table_type.set_function("set_memory_modified_func", - [this] (symbol_table_wrapper &st, sol::object cb) + [] (symbol_table_wrapper &st, sol::object cb) { if (cb == sol::lua_nil) st.table().set_memory_modified_func(nullptr); else if (cb.is()) - st.table().set_memory_modified_func([this, cbfunc = cb.as()] () { invoke(cbfunc); }); + st.table().set_memory_modified_func([cbfunc = cb.as()] () { invoke(cbfunc); }); else osd_printf_error("[LUA ERROR] must call set_memory_modified_func with function or nil\n"); }); @@ -246,19 +246,19 @@ void lua_engine::initialize_debug(sol::table &emu) { return do_add_symbol(st, name, getter, std::nullopt, nullptr); }, - [this] (symbol_table_wrapper &st, char const *name, int minparams, int maxparams, sol::protected_function execute) -> symbol_entry & + [] (symbol_table_wrapper &st, sol::this_state s, char const *name, int minparams, int maxparams, sol::protected_function execute) -> symbol_entry & { return st.table().add( name, minparams, maxparams, - [this, cbref = sol::reference(execute)] (int numparams, u64 const *paramlist) -> u64 + [L = s.L, cbref = sol::reference(execute)] (int numparams, u64 const *paramlist) -> u64 { - sol::stack_reference traceback(m_lua_state, -sol::stack::push(m_lua_state, sol::default_traceback_error_handler)); + sol::stack_reference traceback(L, -sol::stack::push(L, sol::default_traceback_error_handler)); cbref.push(); - sol::stack_aligned_stack_handler_function func(m_lua_state, -1, traceback); + sol::stack_aligned_stack_handler_function func(L, -1, traceback); for (int i = 0; numparams > i; ++i) - lua_pushinteger(m_lua_state, paramlist[i]); + lua_pushinteger(L, paramlist[i]); auto result = func(sol::stack_count(numparams)).get >(); traceback.pop(); return result ? *result : 0; diff --git a/src/frontend/mame/luaengine_mem.cpp b/src/frontend/mame/luaengine_mem.cpp index f22d23b0961..1bbf7c24431 100644 --- a/src/frontend/mame/luaengine_mem.cpp +++ b/src/frontend/mame/luaengine_mem.cpp @@ -195,7 +195,6 @@ public: tap_helper(tap_helper &&) = delete; tap_helper( - lua_engine &engine, address_space &space, read_or_write mode, offs_t start, @@ -203,7 +202,6 @@ public: std::string &&name, sol::protected_function &&callback) : m_callback(std::move(callback)) - , m_engine(engine) , m_space(space) , m_handler() , m_name(std::move(name)) @@ -270,7 +268,7 @@ private: m_name, [this] (offs_t offset, T &data, T mem_mask) { - auto result = m_engine.invoke(m_callback, offset, data, mem_mask).template get >(); + auto result = invoke(m_callback, offset, data, mem_mask).template get >(); if (result) data = *result; }, @@ -283,7 +281,7 @@ private: m_name, [this] (offs_t offset, T &data, T mem_mask) { - auto result = m_engine.invoke(m_callback, offset, data, mem_mask).template get >(); + auto result = invoke(m_callback, offset, data, mem_mask).template get >(); if (result) data = *result; }, @@ -303,7 +301,6 @@ private: }; sol::protected_function m_callback; - lua_engine &m_engine; address_space &m_space; memory_passthrough_handler m_handler; std::string m_name; @@ -531,118 +528,125 @@ void lua_engine::initialize_memory(sol::table &emu) { auto addr_space_type = sol().registry().new_usertype("addr_space", sol::no_constructor); - addr_space_type["read_i8"] = &addr_space::mem_read; - addr_space_type["read_u8"] = &addr_space::mem_read; - addr_space_type["read_i16"] = &addr_space::mem_read; - addr_space_type["read_u16"] = &addr_space::mem_read; - addr_space_type["read_i32"] = &addr_space::mem_read; - addr_space_type["read_u32"] = &addr_space::mem_read; - addr_space_type["read_i64"] = &addr_space::mem_read; - addr_space_type["read_u64"] = &addr_space::mem_read; - addr_space_type["write_i8"] = &addr_space::mem_write; - addr_space_type["write_u8"] = &addr_space::mem_write; - addr_space_type["write_i16"] = &addr_space::mem_write; - addr_space_type["write_u16"] = &addr_space::mem_write; - addr_space_type["write_i32"] = &addr_space::mem_write; - addr_space_type["write_u32"] = &addr_space::mem_write; - addr_space_type["write_i64"] = &addr_space::mem_write; - addr_space_type["write_u64"] = &addr_space::mem_write; - addr_space_type["readv_i8"] = &addr_space::log_mem_read; - addr_space_type["readv_u8"] = &addr_space::log_mem_read; - addr_space_type["readv_i16"] = &addr_space::log_mem_read; - addr_space_type["readv_u16"] = &addr_space::log_mem_read; - addr_space_type["readv_i32"] = &addr_space::log_mem_read; - addr_space_type["readv_u32"] = &addr_space::log_mem_read; - addr_space_type["readv_i64"] = &addr_space::log_mem_read; - addr_space_type["readv_u64"] = &addr_space::log_mem_read; - addr_space_type["writev_i8"] = &addr_space::log_mem_write; - addr_space_type["writev_u8"] = &addr_space::log_mem_write; - addr_space_type["writev_i16"] = &addr_space::log_mem_write; - addr_space_type["writev_u16"] = &addr_space::log_mem_write; - addr_space_type["writev_i32"] = &addr_space::log_mem_write; - addr_space_type["writev_u32"] = &addr_space::log_mem_write; - addr_space_type["writev_i64"] = &addr_space::log_mem_write; - addr_space_type["writev_u64"] = &addr_space::log_mem_write; - addr_space_type["read_direct_i8"] = &addr_space::direct_mem_read; - addr_space_type["read_direct_u8"] = &addr_space::direct_mem_read; - addr_space_type["read_direct_i16"] = &addr_space::direct_mem_read; - addr_space_type["read_direct_u16"] = &addr_space::direct_mem_read; - addr_space_type["read_direct_i32"] = &addr_space::direct_mem_read; - addr_space_type["read_direct_u32"] = &addr_space::direct_mem_read; - addr_space_type["read_direct_i64"] = &addr_space::direct_mem_read; - addr_space_type["read_direct_u64"] = &addr_space::direct_mem_read; - addr_space_type["write_direct_i8"] = &addr_space::direct_mem_write; - addr_space_type["write_direct_u8"] = &addr_space::direct_mem_write; - addr_space_type["write_direct_i16"] = &addr_space::direct_mem_write; - addr_space_type["write_direct_u16"] = &addr_space::direct_mem_write; - addr_space_type["write_direct_i32"] = &addr_space::direct_mem_write; - addr_space_type["write_direct_u32"] = &addr_space::direct_mem_write; - addr_space_type["write_direct_i64"] = &addr_space::direct_mem_write; - addr_space_type["write_direct_u64"] = &addr_space::direct_mem_write; - addr_space_type["read_range"] = + addr_space_type.set_function(sol::meta_function::to_string, + [] (addr_space const &sp) + { + device_t &d(sp.dev.device()); + return util::string_format("%s(%s):%s", d.shortname(), d.tag(), sp.space.name()); + }); + addr_space_type.set_function("read_i8", &addr_space::mem_read); + addr_space_type.set_function("read_u8", &addr_space::mem_read); + addr_space_type.set_function("read_i16", &addr_space::mem_read); + addr_space_type.set_function("read_u16", &addr_space::mem_read); + addr_space_type.set_function("read_i32", &addr_space::mem_read); + addr_space_type.set_function("read_u32", &addr_space::mem_read); + addr_space_type.set_function("read_i64", &addr_space::mem_read); + addr_space_type.set_function("read_u64", &addr_space::mem_read); + addr_space_type.set_function("write_i8", &addr_space::mem_write); + addr_space_type.set_function("write_u8", &addr_space::mem_write); + addr_space_type.set_function("write_i16", &addr_space::mem_write); + addr_space_type.set_function("write_u16", &addr_space::mem_write); + addr_space_type.set_function("write_i32", &addr_space::mem_write); + addr_space_type.set_function("write_u32", &addr_space::mem_write); + addr_space_type.set_function("write_i64", &addr_space::mem_write); + addr_space_type.set_function("write_u64", &addr_space::mem_write); + addr_space_type.set_function("readv_i8", &addr_space::log_mem_read); + addr_space_type.set_function("readv_u8", &addr_space::log_mem_read); + addr_space_type.set_function("readv_i16", &addr_space::log_mem_read); + addr_space_type.set_function("readv_u16", &addr_space::log_mem_read); + addr_space_type.set_function("readv_i32", &addr_space::log_mem_read); + addr_space_type.set_function("readv_u32", &addr_space::log_mem_read); + addr_space_type.set_function("readv_i64", &addr_space::log_mem_read); + addr_space_type.set_function("readv_u64", &addr_space::log_mem_read); + addr_space_type.set_function("writev_i8", &addr_space::log_mem_write); + addr_space_type.set_function("writev_u8", &addr_space::log_mem_write); + addr_space_type.set_function("writev_i16", &addr_space::log_mem_write); + addr_space_type.set_function("writev_u16", &addr_space::log_mem_write); + addr_space_type.set_function("writev_i32", &addr_space::log_mem_write); + addr_space_type.set_function("writev_u32", &addr_space::log_mem_write); + addr_space_type.set_function("writev_i64", &addr_space::log_mem_write); + addr_space_type.set_function("writev_u64", &addr_space::log_mem_write); + addr_space_type.set_function("read_direct_i8", &addr_space::direct_mem_read); + addr_space_type.set_function("read_direct_u8", &addr_space::direct_mem_read); + addr_space_type.set_function("read_direct_i16", &addr_space::direct_mem_read); + addr_space_type.set_function("read_direct_u16", &addr_space::direct_mem_read); + addr_space_type.set_function("read_direct_i32", &addr_space::direct_mem_read); + addr_space_type.set_function("read_direct_u32", &addr_space::direct_mem_read); + addr_space_type.set_function("read_direct_i64", &addr_space::direct_mem_read); + addr_space_type.set_function("read_direct_u64", &addr_space::direct_mem_read); + addr_space_type.set_function("write_direct_i8", &addr_space::direct_mem_write); + addr_space_type.set_function("write_direct_u8", &addr_space::direct_mem_write); + addr_space_type.set_function("write_direct_i16", &addr_space::direct_mem_write); + addr_space_type.set_function("write_direct_u16", &addr_space::direct_mem_write); + addr_space_type.set_function("write_direct_i32", &addr_space::direct_mem_write); + addr_space_type.set_function("write_direct_u32", &addr_space::direct_mem_write); + addr_space_type.set_function("write_direct_i64", &addr_space::direct_mem_write); + addr_space_type.set_function("write_direct_u64", &addr_space::direct_mem_write); + addr_space_type.set_function("read_range", [] (addr_space &sp, sol::this_state s, u64 first, u64 last, int width, sol::object opt_step) -> sol::object { - lua_State *L = s; - luaL_Buffer buff; - offs_t space_size = sp.space.addrmask(); u64 step = 1; if (opt_step.is()) { step = opt_step.as(); - if (step < 1 || step > last - first) + if ((step < 1) || (step > last - first)) { - luaL_error(L, "Invalid step"); + luaL_error(s, "Invalid step"); return sol::lua_nil; } } - if (first > space_size || last > space_size || last < first) + + offs_t space_size = sp.space.addrmask(); + if ((first > space_size) || (last > space_size) || (last < first)) { - luaL_error(L, "Invalid offset"); + luaL_error(s, "Invalid offset"); return sol::lua_nil; } + + luaL_Buffer buff; int byte_count = width / 8 * (last - first + 1) / step; switch (width) { case 8: { - u8 *dest = (u8 *)luaL_buffinitsize(L, &buff, byte_count); + u8 *dest = (u8 *)luaL_buffinitsize(s, &buff, byte_count); for ( ; first <= last; first += step) *dest++ = sp.mem_read(first); break; } case 16: { - u16 *dest = (u16 *)luaL_buffinitsize(L, &buff, byte_count); + u16 *dest = (u16 *)luaL_buffinitsize(s, &buff, byte_count); for ( ; first <= last; first += step) *dest++ = sp.mem_read(first); break; } case 32: { - u32 *dest = (u32 *)luaL_buffinitsize(L, &buff, byte_count); + u32 *dest = (u32 *)luaL_buffinitsize(s, &buff, byte_count); for( ; first <= last; first += step) *dest++ = sp.mem_read(first); break; } case 64: { - u64 *dest = (u64 *)luaL_buffinitsize(L, &buff, byte_count); + u64 *dest = (u64 *)luaL_buffinitsize(s, &buff, byte_count); for( ; first <= last; first += step) *dest++ = sp.mem_read(first); break; } default: - luaL_error(L, "Invalid width. Must be 8/16/32/64"); + luaL_error(s, "Invalid width. Must be 8/16/32/64"); return sol::lua_nil; } luaL_pushresultsize(&buff, byte_count); - return sol::make_reference(L, sol::stack_reference(L, -1)); - }; - addr_space_type["add_change_notifier"] = - [this] (addr_space &sp, sol::protected_function &&cb) + return sol::make_reference(s, sol::stack_reference(s, -1)); + }); + addr_space_type.set_function("add_change_notifier", + [] (addr_space &sp, sol::protected_function &&cb) { return sp.space.add_change_notifier( - [this, callback = std::move(cb)] (read_or_write mode) + [callback = std::move(cb)] (read_or_write mode) { char const *modestr = ""; switch (mode) @@ -653,17 +657,17 @@ void lua_engine::initialize_memory(sol::table &emu) } invoke(callback, modestr); }); - }; - addr_space_type["install_read_tap"] = - [this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) + }); + addr_space_type.set_function("install_read_tap", + [] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) { - return std::make_unique(*this, sp.space, read_or_write::READ, start, end, std::move(name), std::move(cb)); - }; - addr_space_type["install_write_tap"] = - [this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) + return std::make_unique(sp.space, read_or_write::READ, start, end, std::move(name), std::move(cb)); + }); + addr_space_type.set_function("install_write_tap", + [] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) { - return std::make_unique(*this, sp.space, read_or_write::WRITE, start, end, std::move(name), std::move(cb)); - }; + return std::make_unique(sp.space, read_or_write::WRITE, start, end, std::move(name), std::move(cb)); + }); addr_space_type["name"] = sol::property([] (addr_space &sp) { return sp.space.name(); }); addr_space_type["shift"] = sol::property([] (addr_space &sp) { return sp.space.addr_shift(); }); addr_space_type["index"] = sol::property([] (addr_space &sp) { return sp.space.spacenum(); }); @@ -674,8 +678,8 @@ void lua_engine::initialize_memory(sol::table &emu) auto tap_type = sol().registry().new_usertype("mempassthrough", sol::no_constructor); - tap_type["reinstall"] = &tap_helper::reinstall; - tap_type["remove"] = &tap_helper::remove; + tap_type.set_function("reinstall", &tap_helper::reinstall); + tap_type.set_function("remove", &tap_helper::remove); tap_type["addrstart"] = sol::property(&tap_helper::start); tap_type["addrend"] = sol::property(&tap_helper::end); tap_type["name"] = sol::property(&tap_helper::name); @@ -722,22 +726,22 @@ void lua_engine::initialize_memory(sol::table &emu) auto region_type = sol().registry().new_usertype("region", sol::no_constructor); - region_type["read_i8"] = ®ion_read; - region_type["read_u8"] = ®ion_read; - region_type["read_i16"] = ®ion_read; - region_type["read_u16"] = ®ion_read; - region_type["read_i32"] = ®ion_read; - region_type["read_u32"] = ®ion_read; - region_type["read_i64"] = ®ion_read; - region_type["read_u64"] = ®ion_read; - region_type["write_i8"] = ®ion_write; - region_type["write_u8"] = ®ion_write; - region_type["write_i16"] = ®ion_write; - region_type["write_u16"] = ®ion_write; - region_type["write_i32"] = ®ion_write; - region_type["write_u32"] = ®ion_write; - region_type["write_i64"] = ®ion_write; - region_type["write_u64"] = ®ion_write; + region_type.set_function("read_i8", ®ion_read); + region_type.set_function("read_u8", ®ion_read); + region_type.set_function("read_i16", ®ion_read); + region_type.set_function("read_u16", ®ion_read); + region_type.set_function("read_i32", ®ion_read); + region_type.set_function("read_u32", ®ion_read); + region_type.set_function("read_i64", ®ion_read); + region_type.set_function("read_u64", ®ion_read); + region_type.set_function("write_i8", ®ion_write); + region_type.set_function("write_u8", ®ion_write); + region_type.set_function("write_i16", ®ion_write); + region_type.set_function("write_u16", ®ion_write); + region_type.set_function("write_i32", ®ion_write); + region_type.set_function("write_u32", ®ion_write); + region_type.set_function("write_i64", ®ion_write); + region_type.set_function("write_u64", ®ion_write); region_type["tag"] = sol::property(&memory_region::name); region_type["size"] = sol::property(&memory_region::bytes); region_type["length"] = sol::property([] (memory_region &r) { return r.bytes() / r.bytewidth(); }); @@ -747,22 +751,22 @@ void lua_engine::initialize_memory(sol::table &emu) auto share_type = sol().registry().new_usertype("share", sol::no_constructor); - share_type["read_i8"] = &share_read; - share_type["read_u8"] = &share_read; - share_type["read_i16"] = &share_read; - share_type["read_u16"] = &share_read; - share_type["read_i32"] = &share_read; - share_type["read_u32"] = &share_read; - share_type["read_i64"] = &share_read; - share_type["read_u64"] = &share_read; - share_type["write_i8"] = &share_write; - share_type["write_u8"] = &share_write; - share_type["write_i16"] = &share_write; - share_type["write_u16"] = &share_write; - share_type["write_i32"] = &share_write; - share_type["write_u32"] = &share_write; - share_type["write_i64"] = &share_write; - share_type["write_u64"] = &share_write; + share_type.set_function("read_i8", &share_read); + share_type.set_function("read_u8", &share_read); + share_type.set_function("read_i16", &share_read); + share_type.set_function("read_u16", &share_read); + share_type.set_function("read_i32", &share_read); + share_type.set_function("read_u32", &share_read); + share_type.set_function("read_i64", &share_read); + share_type.set_function("read_u64", &share_read); + share_type.set_function("write_i8", &share_write); + share_type.set_function("write_u8", &share_write); + share_type.set_function("write_i16", &share_write); + share_type.set_function("write_u16", &share_write); + share_type.set_function("write_i32", &share_write); + share_type.set_function("write_u32", &share_write); + share_type.set_function("write_i64", &share_write); + share_type.set_function("write_u64", &share_write); share_type["tag"] = sol::property(&memory_share::name); share_type["size"] = sol::property(&memory_share::bytes); share_type["length"] = sol::property([] (memory_share &s) { return s.bytes() / s.bytewidth(); }); diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp index 486f3a8db66..75e487f8753 100644 --- a/src/frontend/mame/mame.cpp +++ b/src/frontend/mame/mame.cpp @@ -203,8 +203,29 @@ void mame_machine_manager::start_luaengine() if (!filerr) { std::string exppath; - osd_subst_env(exppath, std::string(file.fullpath())); - m_lua->load_script(exppath.c_str()); + osd_subst_env(exppath, file.fullpath()); + auto &l(*lua()); + auto load_result = l.load_script(exppath); + if (!load_result.valid()) + { + sol::error err = load_result; + sol::load_status status = load_result.status(); + fatalerror("Error plugin bootstrap script %s: %s error\n%s\n", + exppath, + sol::to_string(status), + err.what()); + } + sol::protected_function func = load_result; + sol::protected_function_result call_result = l.invoke(func); + if (!call_result.valid()) + { + sol::error err = call_result; + sol::call_status status = call_result.status(); + fatalerror("Error running plugin bootstrap script %s: %s error\n%s\n", + options().autoboot_script(), + sol::to_string(status), + err.what()); + } } } } @@ -295,21 +316,35 @@ int mame_machine_manager::execute() TIMER_CALLBACK_MEMBER(mame_machine_manager::autoboot_callback) { - if (strlen(options().autoboot_script())!=0) { - mame_machine_manager::instance()->lua()->load_script(options().autoboot_script()); + if (*options().autoboot_script()) + { + assert(m_autoboot_script); + sol::protected_function func = *m_autoboot_script; + sol::protected_function_result result = lua()->invoke(func); + if (!result.valid()) + { + sol::error err = result; + sol::call_status status = result.status(); + fatalerror("Error running autoboot script %s: %s error\n%s\n", + options().autoboot_script(), + sol::to_string(status), + err.what()); + } } - else if (strlen(options().autoboot_command())!=0) { - std::string cmd = std::string(options().autoboot_command()); + else if (*options().autoboot_command()) + { + std::string cmd(options().autoboot_command()); strreplace(cmd, "'", "\\'"); std::string val = std::string("emu.keypost('").append(cmd).append("')"); - mame_machine_manager::instance()->lua()->load_string(val.c_str()); + auto &l(*lua()); + l.invoke(l.load_string(val)); } } void mame_machine_manager::reset() { // setup autoboot if needed - m_autoboot_timer->adjust(attotime(options().autoboot_delay(),0),0); + m_autoboot_timer->adjust(attotime(options().autoboot_delay(), 0), 0); } ui_manager* mame_machine_manager::create_ui(running_machine& machine) @@ -337,7 +372,7 @@ void mame_machine_manager::before_load_settings(running_machine& machine) m_lua->on_machine_before_load_settings(); } -void mame_machine_manager::create_custom(running_machine& machine) +void mame_machine_manager::create_custom(running_machine &machine) { // start the inifile manager m_inifile = std::make_unique(m_ui->options()); @@ -347,6 +382,25 @@ void mame_machine_manager::create_custom(running_machine& machine) // start favorite manager m_favorite = std::make_unique(m_ui->options()); + + // attempt to load the autoboot script if configured + m_autoboot_script.reset(); + if (*options().autoboot_script()) + { + auto result = lua()->load_script(options().autoboot_script()); + if (!result.valid()) + { + sol::error err = result; + sol::load_status status = result.status(); + fatalerror("Error loading autoboot script %s: %s error\n%s\n", + options().autoboot_script(), + sol::to_string(status), + err.what()); + } + m_autoboot_script.reset(new sol::load_result(std::move(result))); + sol::protected_function func = *m_autoboot_script; + sol::set_environment(lua()->make_environment(), func); + } } void mame_machine_manager::load_cheatfiles(running_machine& machine) diff --git a/src/frontend/mame/mame.h b/src/frontend/mame/mame.h index 5fb5a2f4a81..a850cf51083 100644 --- a/src/frontend/mame/mame.h +++ b/src/frontend/mame/mame.h @@ -12,6 +12,12 @@ #pragma once +namespace sol { + +struct load_result; + +} // namespace sol + class plugin_options; class osd_interface; @@ -71,19 +77,20 @@ private: mame_machine_manager &operator=(mame_machine_manager const &) = delete; mame_machine_manager &operator=(mame_machine_manager &&) = delete; - std::unique_ptr m_plugins; // pointer to plugin options - std::unique_ptr m_lua; + std::unique_ptr m_plugins; // pointer to plugin options + std::unique_ptr m_lua; - const game_driver * m_new_driver_pending; // pointer to the next pending driver + const game_driver * m_new_driver_pending; // pointer to the next pending driver bool m_firstrun; - static mame_machine_manager *s_manager; - emu_timer *m_autoboot_timer; // autoboot timer - std::unique_ptr m_ui; // internal data from ui.cpp - std::unique_ptr m_cheat; // internal data from cheat.cpp - std::unique_ptr m_inifile; // internal data from inifile.c for INIs - std::unique_ptr m_favorite; // internal data from inifile.c for favorites + emu_timer * m_autoboot_timer; // auto-boot timer + std::unique_ptr m_autoboot_script; // auto-boot script + std::unique_ptr m_ui; // internal data from ui.cpp + std::unique_ptr m_cheat; // internal data from cheat.cpp + std::unique_ptr m_inifile; // internal data from inifile.c for INIs + std::unique_ptr m_favorite; // internal data from inifile.c for favorites + static mame_machine_manager *s_manager; }; //**************************************************************************