From 12e0982f3cdb8d1683884847ad628663407706b7 Mon Sep 17 00:00:00 2001 From: npwoods Date: Mon, 5 Aug 2019 11:03:50 -0400 Subject: Changed mechanisms for overriding the mandatory file manager - Removed the -skip_mandatory_fileman command line option - Created an emu.register_mandatory_file_manager_override() LUA function to allow LUA plugins to substitute the mandatory file manager --- src/emu/emuopts.cpp | 1 - src/emu/emuopts.h | 2 -- src/frontend/mame/luaengine.cpp | 56 ++++++++++++++++++++++++++++++++++++----- src/frontend/mame/luaengine.h | 2 ++ src/frontend/mame/mame.cpp | 26 +++++++++++++++++++ src/frontend/mame/mame.h | 2 ++ src/frontend/mame/ui/info.cpp | 29 --------------------- src/frontend/mame/ui/info.h | 1 - src/frontend/mame/ui/ui.cpp | 39 ++++++++++++++++++++++------ 9 files changed, 112 insertions(+), 46 deletions(-) diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp index 1d52bc958d5..eb7c9bdbf27 100644 --- a/src/emu/emuopts.cpp +++ b/src/emu/emuopts.cpp @@ -193,7 +193,6 @@ const options_entry emu_options::s_option_entries[] = { OPTION_BIOS, nullptr, OPTION_STRING, "select the system BIOS to use" }, { OPTION_CHEAT ";c", "0", OPTION_BOOLEAN, "enable cheat subsystem" }, { OPTION_SKIP_GAMEINFO, "0", OPTION_BOOLEAN, "skip displaying the system information screen at startup" }, - { OPTION_SKIP_MANDATORY_FILEMAN, "0", OPTION_BOOLEAN, "skip prompting the user for any mandatory images with the file manager at startup" }, { OPTION_UI_FONT, "default", OPTION_STRING, "specify a font to use" }, { OPTION_UI, "cabinet", OPTION_STRING, "type of UI (simple|cabinet)" }, { OPTION_RAMSIZE ";ram", nullptr, OPTION_STRING, "size of RAM (if supported by driver)" }, diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h index 1036d3c3e06..970a90c67da 100644 --- a/src/emu/emuopts.h +++ b/src/emu/emuopts.h @@ -162,7 +162,6 @@ #define OPTION_BIOS "bios" #define OPTION_CHEAT "cheat" #define OPTION_SKIP_GAMEINFO "skip_gameinfo" -#define OPTION_SKIP_MANDATORY_FILEMAN "skip_mandatory_fileman" #define OPTION_UI_FONT "uifont" #define OPTION_UI "ui" #define OPTION_RAMSIZE "ramsize" @@ -438,7 +437,6 @@ public: const char *bios() const { return value(OPTION_BIOS); } bool cheat() const { return bool_value(OPTION_CHEAT); } bool skip_gameinfo() const { return bool_value(OPTION_SKIP_GAMEINFO); } - bool skip_mandatory_fileman() const { return bool_value(OPTION_SKIP_MANDATORY_FILEMAN); } const char *ui_font() const { return value(OPTION_UI_FONT); } ui_option ui() const { return m_ui; } const char *ram_size() const { return value(OPTION_RAMSIZE); } diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index bb4c585516a..0182a5cbeeb 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -650,17 +650,23 @@ bool lua_engine::menu_callback(const std::string &menu, int index, const std::st return ret; } -bool lua_engine::execute_function(const char *id) +int lua_engine::enumerate_functions(const char *id, std::function &&callback) { + int count = 0; sol::object functable = sol().registry()[id]; - if(functable.is()) + if (functable.is()) { - for(auto &func : functable.as()) + for (auto &func : functable.as()) { - if(func.second.is()) + if (func.second.is()) { + bool cont = callback(func.second.as()); + count++; + if (!cont) + break; + auto ret = invoke(func.second.as()); - if(!ret.valid()) + if (!ret.valid()) { sol::error err = ret; osd_printf_error("[LUA ERROR] in execute_function: %s\n", err.what()); @@ -669,7 +675,22 @@ bool lua_engine::execute_function(const char *id) } return true; } - return false; + return count; +} + +bool lua_engine::execute_function(const char *id) +{ + int count = enumerate_functions(id, [this](const sol::protected_function &func) + { + auto ret = invoke(func); + if(!ret.valid()) + { + sol::error err = ret; + osd_printf_error("[LUA ERROR] in execute_function: %s\n", err.what()); + } + return true; + }); + return count > 0; } void lua_engine::register_function(sol::function func, const char *id) @@ -721,6 +742,27 @@ void lua_engine::on_periodic() execute_function("LUA_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); + + 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; +} + void lua_engine::attach_notifiers() { machine().add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(&lua_engine::on_machine_prestart, this), true); @@ -767,6 +809,7 @@ void lua_engine::initialize() * emu.register_periodic(callback) - register periodic callback while program is running * emu.register_callback(callback, name) - register callback to be used by MAME via lua_engine::call_plugin() * emu.register_menu(event_callback, populate_callback, name) - register callbacks for plugin menu + * emu.register_mandatory_file_manager_override(callback) - register callback invoked to override mandatory file manager * emu.show_menu(menu_name) - show menu by name and pause the machine * * emu.print_verbose(str) - output to stderr at verbose level @@ -806,6 +849,7 @@ void lua_engine::initialize() emu["register_frame"] = [this](sol::function func){ register_function(func, "LUA_ON_FRAME"); }; emu["register_frame_done"] = [this](sol::function func){ register_function(func, "LUA_ON_FRAME_DONE"); }; emu["register_periodic"] = [this](sol::function func){ register_function(func, "LUA_ON_PERIODIC"); }; + emu["register_mandatory_file_manager_override"] = [this](sol::function func) { register_function(func, "LUA_ON_MANDATORY_FILE_MANAGER_OVERRIDE"); }; emu["register_menu"] = [this](sol::function cb, sol::function pop, const std::string &name) { std::string cbfield = "menu_cb_" + name; std::string popfield = "menu_pop_" + name; diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index 2937b723b74..b5938d2aee8 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -50,6 +50,7 @@ public: void attach_notifiers(); void on_frame_done(); void on_periodic(); + bool on_missing_mandatory_image(const std::string &instance_name); template bool call_plugin(const std::string &name, const T in, U &out) @@ -126,6 +127,7 @@ private: void resume(void *ptr, int nparam); void register_function(sol::function func, const char *id); + int enumerate_functions(const char *id, std::function &&callback); bool execute_function(const char *id); sol::object call_plugin(const std::string &name, sol::object in); diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp index b7ec46717d3..1266370fe4b 100644 --- a/src/frontend/mame/mame.cpp +++ b/src/frontend/mame/mame.cpp @@ -341,6 +341,32 @@ void mame_machine_manager::load_cheatfiles(running_machine& machine) m_cheat = std::make_unique(machine); } +//------------------------------------------------- +// missing_mandatory_images - search for devices +// which need an image to be loaded +//------------------------------------------------- + +std::vector> mame_machine_manager::missing_mandatory_images() +{ + std::vector> results; + assert(m_machine); + + // make sure that any required image has a mounted file + for (device_image_interface &image : image_interface_iterator(m_machine->root_device())) + { + if (image.must_be_loaded()) + { + if (m_machine->options().image_option(image.instance_name()).value().empty()) + { + // this is a missing image; give LUA plugins a chance to handle it + if (!lua()->on_missing_mandatory_image(image.instance_name())) + results.push_back(std::reference_wrapper(image.instance_name())); + } + } + } + return results; +} + const char * emulator_info::get_bare_build_version() { return bare_build_version; } const char * emulator_info::get_build_version() { return build_version; } diff --git a/src/frontend/mame/mame.h b/src/frontend/mame/mame.h index 01a7235972b..36a284ed978 100644 --- a/src/frontend/mame/mame.h +++ b/src/frontend/mame/mame.h @@ -50,6 +50,8 @@ public: virtual void ui_initialize(running_machine& machine) override; + std::vector> missing_mandatory_images(); + /* execute as configured by the OPTION_SYSTEMNAME option on the specified options */ int execute(); void start_luaengine(); diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp index 46d092722d2..b28af0eb817 100644 --- a/src/frontend/mame/ui/info.cpp +++ b/src/frontend/mame/ui/info.cpp @@ -407,35 +407,6 @@ std::string machine_info::game_info_string() const } -//------------------------------------------------- -// mandatory_images - search for devices which -// need an image to be loaded -//------------------------------------------------- - -std::string machine_info::mandatory_images() const -{ - std::ostringstream buf; - bool is_first = true; - - // make sure that any required image has a mounted file - for (device_image_interface &image : image_interface_iterator(m_machine.root_device())) - { - if (image.must_be_loaded()) - { - if (m_machine.options().image_option(image.instance_name()).value().empty()) - { - if (is_first) - is_first = false; - else - buf << ", "; - buf << "\"" << image.instance_name() << "\""; - } - } - } - return buf.str(); -} - - //------------------------------------------------- // get_screen_desc - returns the description for // a given screen diff --git a/src/frontend/mame/ui/info.h b/src/frontend/mame/ui/info.h index 2aa5b99c63c..a3746ce6b03 100644 --- a/src/frontend/mame/ui/info.h +++ b/src/frontend/mame/ui/info.h @@ -76,7 +76,6 @@ public: // text generators std::string warnings_string() const; std::string game_info_string() const; - std::string mandatory_images() const; std::string get_screen_desc(screen_device &screen) const; private: diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp index e3d48c13be1..ce1ea2855c1 100644 --- a/src/frontend/mame/ui/ui.cpp +++ b/src/frontend/mame/ui/ui.cpp @@ -273,6 +273,26 @@ void mame_ui_manager::set_handler(ui_callback_type callback_type, const std::fun } +//------------------------------------------------- +// output_joined_collection +//------------------------------------------------- + +template +static void output_joined_collection(const TColl &collection, TEmitMemberFunc emit_member, TEmitDelimFunc emit_delim) +{ + bool is_first = true; + + for (const auto &member : collection) + { + if (is_first) + is_first = false; + else + emit_delim(); + emit_member(member); + } +} + + //------------------------------------------------- // display_startup_screens - display the // various startup screens @@ -283,13 +303,13 @@ void mame_ui_manager::display_startup_screens(bool first_time) const int maxstate = 3; int str = machine().options().seconds_to_run(); bool show_gameinfo = !machine().options().skip_gameinfo(); - bool show_warnings = true, show_mandatory_fileman = !machine().options().skip_mandatory_fileman(); + bool show_warnings = true; bool video_none = strcmp(downcast(machine().options()).video(), "none") == 0; // disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver, // or if we are debugging, or if there's no mame window to send inputs to if (!first_time || (str > 0 && str < 60*5) || &machine().system() == &GAME_NAME(___empty) || (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0 || video_none) - show_gameinfo = show_warnings = show_mandatory_fileman = false; + show_gameinfo = show_warnings = false; #if defined(EMSCRIPTEN) // also disable for the JavaScript port since the startup screens do not run asynchronously @@ -326,12 +346,17 @@ void mame_ui_manager::display_startup_screens(bool first_time) break; case 2: - if (show_mandatory_fileman) - messagebox_text = machine_info().mandatory_images(); - if (!messagebox_text.empty()) + std::vector> mandatory_images = mame_machine_manager::instance()->missing_mandatory_images(); + if (!mandatory_images.empty()) { - std::string warning = std::string(_("This driver requires images to be loaded in the following device(s): ")) + messagebox_text; - ui::menu_file_manager::force_file_manager(*this, machine().render().ui_container(), warning.c_str()); + std::ostringstream warning; + warning << _("This driver requires images to be loaded in the following device(s): "); + + output_joined_collection(mandatory_images, + [&warning](const std::reference_wrapper &img) { warning << "\"" << img.get() << "\""; }, + [&warning]() { warning << ","; }); + + ui::menu_file_manager::force_file_manager(*this, machine().render().ui_container(), warning.str().c_str()); } break; } -- cgit v1.2.3