summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2019-07-24 19:59:17 -0400
committer GitHub <noreply@github.com>2019-07-24 19:59:17 -0400
commit775b486c734d9a5e0c2c8c17c3a3b25f43789180 (patch)
treeb9769607eb616614e17ea4b04c1454223d96d645
parent002fa6688c64c24b3d8be034407ce5b246d4bbe7 (diff)
parentaac4e79d4b62decf5b53683b100525587b5091c8 (diff)
Merge pull request #5383 from npwoods/plugin_refactor
Refactored MAME's plugin system
-rw-r--r--plugins/boot.lua28
-rw-r--r--src/frontend/mame/clifront.cpp3
-rw-r--r--src/frontend/mame/luaengine.cpp15
-rw-r--r--src/frontend/mame/mame.cpp76
-rw-r--r--src/frontend/mame/pluginopts.cpp180
-rw-r--r--src/frontend/mame/pluginopts.h35
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp18
7 files changed, 240 insertions, 115 deletions
diff --git a/plugins/boot.lua b/plugins/boot.lua
index 5ed1ac803ad..98eb14baa86 100644
--- a/plugins/boot.lua
+++ b/plugins/boot.lua
@@ -26,27 +26,11 @@ local dir = lfs.env_replace(manager:options().entries.pluginspath:value())
package.path = dir .. "/?.lua;" .. dir .. "/?/init.lua"
-local json = require('json')
-local function readAll(file)
- local f = io.open(file, "rb")
- local content = f:read("*all")
- f:close()
- return content
-end
-
-for file in lfs.dir(dir) do
- if (file~="." and file~=".." and lfs.attributes(dir .. "/" .. file,"mode")=="directory") then
- local filename = dir .. "/" .. file .. "/plugin.json"
- local meta = json.parse(readAll(filename))
- if (meta["plugin"]["type"]=="plugin") and (mame_manager:plugins().entries[meta["plugin"]["name"]]~=nil) then
- local entry = mame_manager:plugins().entries[meta["plugin"]["name"]]
- if (entry:value()==true) then
- emu.print_verbose("Starting plugin " .. meta["plugin"]["name"] .. "...")
- plugin = require(meta["plugin"]["name"])
- if plugin.set_folder~=nil then plugin.set_folder(dir .. "/" .. file) end
- plugin.startplugin();
- end
- end
+for _,entry in pairs(manager:plugins()) do
+ if (entry.type == "plugin" and entry.start) then
+ emu.print_verbose("Starting plugin " .. entry.name .. "...")
+ plugin = require(entry.name)
+ if plugin.set_folder~=nil then plugin.set_folder(entry.directory) end
+ plugin.startplugin();
end
end
-
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 7a364f4996a..3c0e5c21544 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -1666,7 +1666,8 @@ void cli_frontend::execute_commands(const char *exename)
std::string pluginpath;
while (iter.next(pluginpath))
{
- plugin_opts.parse_json(pluginpath);
+ osd_subst_env(pluginpath, pluginpath);
+ plugin_opts.scan_directory(pluginpath, true);
}
emu_file file_plugin(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
if (file_plugin.open("plugin.ini") != osd_file::error::NONE)
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 8ca06e1459e..77345cc53f2 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -2507,7 +2507,20 @@ void lua_engine::initialize()
sol().registry().new_usertype<mame_machine_manager>("manager", "new", sol::no_constructor,
"machine", &machine_manager::machine,
"options", [](mame_machine_manager &m) { return static_cast<core_options *>(&m.options()); },
- "plugins", [](mame_machine_manager &m) { return static_cast<core_options *>(&m.plugins()); },
+ "plugins", [this](mame_machine_manager &m) {
+ sol::table table = sol().create_table();
+ for (auto &curentry : m.plugins().plugins())
+ {
+ sol::table plugin_table = sol().create_table();
+ plugin_table["name"] = curentry.m_name;
+ plugin_table["description"] = curentry.m_description;
+ plugin_table["type"] = curentry.m_type;
+ plugin_table["directory"] = curentry.m_directory;
+ plugin_table["start"] = curentry.m_start;
+ table[curentry.m_name] = plugin_table;
+ }
+ return table;
+ },
"ui", &mame_machine_manager::ui);
sol()["manager"] = std::ref(*mame_machine_manager::instance());
sol()["mame_manager"] = std::ref(*mame_machine_manager::instance());
diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp
index f3c08f661e9..9334cb3445b 100644
--- a/src/frontend/mame/mame.cpp
+++ b/src/frontend/mame/mame.cpp
@@ -88,6 +88,11 @@ void mame_machine_manager::schedule_new_driver(const game_driver &driver)
/***************************************************************************
CORE IMPLEMENTATION
***************************************************************************/
+
+//-------------------------------------------------
+// update_machine
+//-------------------------------------------------
+
void mame_machine_manager::update_machine()
{
m_lua->set_machine(m_machine);
@@ -95,7 +100,11 @@ void mame_machine_manager::update_machine()
}
-std::vector<std::string> split(const std::string &text, char sep)
+//-------------------------------------------------
+// split
+//-------------------------------------------------
+
+static std::vector<std::string> split(const std::string &text, char sep)
{
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
@@ -110,18 +119,27 @@ std::vector<std::string> split(const std::string &text, char sep)
return tokens;
}
+
+//-------------------------------------------------
+// start_luaengine
+//-------------------------------------------------
+
void mame_machine_manager::start_luaengine()
{
if (options().plugins())
{
+ // scan all plugin directories
path_iterator iter(options().plugins_path());
std::string pluginpath;
while (iter.next(pluginpath))
{
- m_plugins->parse_json(pluginpath);
+ // user may specify environment variables; subsitute them
+ osd_subst_env(pluginpath, pluginpath);
+
+ // and then scan the directory recursively
+ m_plugins->scan_directory(pluginpath, true);
}
- std::vector<std::string> include = split(options().plugin(), ',');
- std::vector<std::string> exclude = split(options().no_plugin(), ',');
+
{
// parse the file
// attempt to open the output file
@@ -130,7 +148,7 @@ void mame_machine_manager::start_luaengine()
{
try
{
- m_plugins->parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_MAME_INI < OPTION_PRIORITY_DRIVER_INI, false);
+ m_plugins->parse_ini_file((util::core_file&)file);
}
catch (options_exception &)
{
@@ -138,31 +156,34 @@ void mame_machine_manager::start_luaengine()
}
}
}
- for (auto &curentry : m_plugins->entries())
+
+ // process includes
+ for (const std::string &incl : split(options().plugin(), ','))
{
- if (curentry->type() != core_options::option_type::HEADER)
- {
- if (std::find(include.begin(), include.end(), curentry->name()) != include.end())
- {
- m_plugins->set_value(curentry->name(), "1", OPTION_PRIORITY_CMDLINE);
- }
- if (std::find(exclude.begin(), exclude.end(), curentry->name()) != exclude.end())
- {
- m_plugins->set_value(curentry->name(), "0", OPTION_PRIORITY_CMDLINE);
- }
- }
+ plugin *p = m_plugins->find(incl);
+ if (!p)
+ fatalerror("Could not load plugin: %s\n", incl.c_str());
+ p->m_start = true;
+ }
+
+ // process excludes
+ for (const std::string &excl : split(options().no_plugin(), ','))
+ {
+ plugin *p = m_plugins->find(excl);
+ if (!p)
+ fatalerror("Unknown plugin: %s\n", excl.c_str());
+ p->m_start = false;
}
}
+
+ // we have a special way to open the console plugin
if (options().console())
{
- if (m_plugins->exists(OPTION_CONSOLE))
- {
- m_plugins->set_value(OPTION_CONSOLE, "1", OPTION_PRIORITY_CMDLINE);
- }
- else
- {
+ plugin *p = m_plugins->find(OPTION_CONSOLE);
+ if (!p)
fatalerror("Console plugin not found.\n");
- }
+
+ p->m_start = true;
}
m_lua->initialize();
@@ -179,9 +200,10 @@ void mame_machine_manager::start_luaengine()
}
}
-/*-------------------------------------------------
- execute - run the core emulation
--------------------------------------------------*/
+
+//-------------------------------------------------
+// execute - run the core emulation
+//-------------------------------------------------
int mame_machine_manager::execute()
{
diff --git a/src/frontend/mame/pluginopts.cpp b/src/frontend/mame/pluginopts.cpp
index cfb04af21a4..ef30cf917f3 100644
--- a/src/frontend/mame/pluginopts.cpp
+++ b/src/frontend/mame/pluginopts.cpp
@@ -7,8 +7,10 @@
Plugin options manager.
***************************************************************************/
+
#include "emu.h"
#include "pluginopts.h"
+#include "options.h"
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
@@ -21,77 +23,157 @@
// PLUGIN OPTIONS
//**************************************************************************
-const options_entry plugin_options::s_option_entries[] =
-{
- { nullptr, nullptr, OPTION_HEADER, "PLUGINS OPTIONS" },
- { nullptr }
-};
-
//-------------------------------------------------
// plugin_options - constructor
//-------------------------------------------------
plugin_options::plugin_options()
-: core_options()
{
- add_entries(plugin_options::s_option_entries);
}
-void plugin_options::parse_json(std::string path)
+//-------------------------------------------------
+// scan_directory
+//-------------------------------------------------
+
+void plugin_options::scan_directory(const std::string &path, bool recursive)
{
// first try to open as a directory
- osd_subst_env(path, path);
osd::directory::ptr directory = osd::directory::open(path);
if (directory)
{
// iterate over all files in the directory
for (const osd::directory::entry *entry = directory->read(); entry != nullptr; entry = directory->read())
{
- if (entry->type == osd::directory::entry::entry_type::FILE)
+ if (entry->type == osd::directory::entry::entry_type::FILE && !strcmp(entry->name, "plugin.json"))
{
- std::string name = entry->name;
- if (name == "plugin.json")
- {
- std::string curfile = std::string(path).append(PATH_SEPARATOR).append(entry->name);
- std::ifstream ifs(curfile);
- rapidjson::IStreamWrapper isw(ifs);
- rapidjson::Document document;
- document.ParseStream<0>(isw);
-
- if (document.HasParseError()) {
- std::string error(GetParseError_En(document.GetParseError()));
- osd_printf_error("Unable to parse plugin definition file %s. Errors returned:\n", curfile.c_str());
- osd_printf_error("%s\n", error.c_str());
- return;
- }
-
- if (document["plugin"].IsObject())
- {
- std::string plugin_name = document["plugin"]["name"].GetString();
- std::string description = document["plugin"]["description"].GetString();
- std::string type = document["plugin"]["type"].GetString();
- bool start = false;
- if (document["plugin"].HasMember("start") && (std::string(document["plugin"]["start"].GetString()) == "true"))
- start = true;
-
- if (type=="plugin")
- {
- auto const it = m_descriptions.emplace(m_descriptions.end(), std::move(description));
- add_entry({ std::move(plugin_name) }, it->c_str(), option_type::BOOLEAN, start ? "1" : "0");
- }
- }
-
- }
+ std::string curfile = std::string(path).append(PATH_SEPARATOR).append(entry->name);
+ load_plugin(curfile);
}
else if (entry->type == osd::directory::entry::entry_type::DIR)
{
- std::string name = entry->name;
- if (!(name == "." || name == ".."))
- {
- parse_json(path + PATH_SEPARATOR + name);
- }
+ if (recursive && strcmp(entry->name, ".") && strcmp(entry->name, ".."))
+ scan_directory(path + PATH_SEPARATOR + entry->name, recursive);
}
}
}
}
+
+
+//-------------------------------------------------
+// load_plugin
+//-------------------------------------------------
+
+bool plugin_options::load_plugin(const std::string &path)
+{
+ std::ifstream ifs(path);
+ rapidjson::IStreamWrapper isw(ifs);
+ rapidjson::Document document;
+ document.ParseStream<0>(isw);
+
+ if (document.HasParseError())
+ {
+ std::string error(GetParseError_En(document.GetParseError()));
+ osd_printf_error("Unable to parse plugin definition file %s. Errors returned:\n", path.c_str());
+ osd_printf_error("%s\n", error.c_str());
+ return false;
+ }
+
+ if (!document["plugin"].IsObject())
+ {
+ osd_printf_error("Bad plugin definition file %s:\n", path.c_str());
+ return false;
+ }
+
+ size_t last_path_sep = path.find_last_of(PATH_SEPARATOR[0]);
+ std::string dir = last_path_sep != std::string::npos
+ ? path.substr(0, last_path_sep)
+ : ".";
+
+ plugin p;
+ p.m_name = document["plugin"]["name"].GetString();
+ p.m_description = document["plugin"]["description"].GetString();
+ p.m_type = document["plugin"]["type"].GetString();
+ p.m_directory = std::move(dir);
+ p.m_start = false;
+ if (document["plugin"].HasMember("start") && (std::string(document["plugin"]["start"].GetString()) == "true"))
+ p.m_start = true;
+
+ m_plugins.push_back(std::move(p));
+ return true;
+}
+
+
+//-------------------------------------------------
+// find
+//-------------------------------------------------
+
+plugin *plugin_options::find(const std::string &name)
+{
+ auto iter = std::find_if(
+ m_plugins.begin(),
+ m_plugins.end(),
+ [&name](const plugin &p) { return name == p.m_name; });
+
+ return iter != m_plugins.end()
+ ? &*iter
+ : nullptr;
+}
+
+
+//-------------------------------------------------
+// create_core_options
+//-------------------------------------------------
+
+static void create_core_options(core_options &opts, const plugin_options &plugin_opts)
+{
+ // we're sort of abusing core_options to just get INI file parsing, so we'll build a
+ // core_options structure for the sole purpose of parsing an INI file, and then reflect
+ // the data back
+ static const options_entry s_option_entries[] =
+ {
+ { nullptr, nullptr, OPTION_HEADER, "PLUGINS OPTIONS" },
+ { nullptr }
+ };
+ opts.add_entries(s_option_entries);
+
+ // create an entry for each option
+ for (const plugin &p : plugin_opts.plugins())
+ {
+ opts.add_entry(
+ { p.m_name },
+ nullptr,
+ core_options::option_type::BOOLEAN,
+ p.m_start ? "1" : "0");
+ }
+}
+
+
+//-------------------------------------------------
+// parse_ini_file
+//-------------------------------------------------
+
+void plugin_options::parse_ini_file(util::core_file &inifile)
+{
+ core_options opts;
+ create_core_options(opts, *this);
+
+ // parse the INI file
+ opts.parse_ini_file(inifile, OPTION_PRIORITY_NORMAL, true, true);
+
+ // and reflect these options back
+ for (plugin &p : m_plugins)
+ p.m_start = opts.bool_value(p.m_name.c_str());
+}
+
+
+//-------------------------------------------------
+// output_ini
+//-------------------------------------------------
+
+std::string plugin_options::output_ini() const
+{
+ core_options opts;
+ create_core_options(opts, *this);
+ return opts.output_ini();
+}
diff --git a/src/frontend/mame/pluginopts.h b/src/frontend/mame/pluginopts.h
index 27e57104293..c722fb8e2a2 100644
--- a/src/frontend/mame/pluginopts.h
+++ b/src/frontend/mame/pluginopts.h
@@ -7,27 +7,50 @@
Plugin options manager.
***************************************************************************/
+
#ifndef MAME_FRONTEND_PLUGINOPTS_H
#define MAME_FRONTEND_PLUGINOPTS_H
#pragma once
-#include "options.h"
-
#include <list>
#include <string>
-class plugin_options : public core_options
+// ======================> plugin
+
+struct plugin
+{
+ std::string m_name;
+ std::string m_description;
+ std::string m_type;
+ std::string m_directory;
+ bool m_start;
+};
+
+
+// ======================> plugin_options
+
+class plugin_options
{
public:
plugin_options();
- void parse_json(std::string path);
+ // accessors
+ std::list<plugin> &plugins() { return m_plugins; }
+ const std::list<plugin> &plugins() const { return m_plugins; }
+
+ // methods
+ void scan_directory(const std::string &path, bool recursive);
+ bool load_plugin(const std::string &path);
+ plugin *find(const std::string &name);
+
+ // INI functionality
+ void parse_ini_file(util::core_file &inifile);
+ std::string output_ini() const;
private:
- static const options_entry s_option_entries[];
- std::list<std::string> m_descriptions;
+ std::list<plugin> m_plugins;
};
#endif // MAME_FRONTEND_PLUGINOPTS_H
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index fbb84d0aec3..3591a2a0ae3 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -880,9 +880,12 @@ void menu_plugins_configure::handle()
{
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT || menu_event->iptkey == IPT_UI_SELECT)
{
- int oldval = plugins.int_value((const char*)menu_event->itemref);
- plugins.set_value((const char*)menu_event->itemref, oldval == 1 ? 0 : 1, OPTION_PRIORITY_CMDLINE);
- changed = true;
+ plugin *p = plugins.find((const char*)menu_event->itemref);
+ if (p)
+ {
+ p->m_start = !p->m_start;
+ changed = true;
+ }
}
}
if (changed)
@@ -897,13 +900,10 @@ void menu_plugins_configure::populate(float &customtop, float &custombottom)
{
plugin_options& plugins = mame_machine_manager::instance()->plugins();
- for (auto &curentry : plugins.entries())
+ for (auto &curentry : plugins.plugins())
{
- if (curentry->type() != OPTION_HEADER)
- {
- auto enabled = !strcmp(curentry->value(), "1");
- item_append_on_off(curentry->description(), enabled, 0, (void *)(uintptr_t)curentry->name().c_str());
- }
+ bool enabled = curentry.m_start;
+ item_append_on_off(curentry.m_description, enabled, 0, (void *)(uintptr_t)curentry.m_name.c_str());
}
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + (3.0f * ui().box_tb_border());