mirror of
https://github.com/holub/mame
synced 2025-04-18 22:49:58 +03:00
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.
This commit is contained in:
parent
bb3f3e5abd
commit
e6588480c4
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<sol::protected_function>())
|
||||
if (obj.is<sol::protected_function>())
|
||||
{
|
||||
auto res = invoke(obj.as<sol::protected_function>(), 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<sol::object>();
|
||||
}
|
||||
}
|
||||
return sol::lua_nil;
|
||||
}
|
||||
@ -380,7 +382,7 @@ std::optional<long> lua_engine::menu_populate(const std::string &menu, std::vect
|
||||
}
|
||||
else
|
||||
{
|
||||
std::tuple<sol::table, std::optional<long>, std::string> table = res;
|
||||
std::tuple<sol::table, std::optional<long>, std::optional<std::string> > table = res;
|
||||
for (auto &entry : std::get<0>(table))
|
||||
{
|
||||
if (entry.second.is<sol::table>())
|
||||
@ -389,7 +391,10 @@ std::optional<long> lua_engine::menu_populate(const std::string &menu, std::vect
|
||||
menu_list.emplace_back(enttable.get<std::string, std::string, std::string>(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<long> lua_engine::menu_populate(const std::string &menu, std::vect
|
||||
std::pair<bool, std::optional<long> > lua_engine::menu_callback(const std::string &menu, int index, const std::string &event)
|
||||
{
|
||||
std::string field = "menu_cb_" + menu;
|
||||
std::pair<bool, std::optional<long> > ret(false, std::nullopt);
|
||||
std::pair<std::optional<bool>, std::optional<long> > ret(false, std::nullopt);
|
||||
sol::object obj = sol().registry()[field];
|
||||
if (obj.is<sol::protected_function>())
|
||||
{
|
||||
@ -415,7 +420,7 @@ std::pair<bool, std::optional<long> > 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<bool(const sol::protected_function &func)> &&callback)
|
||||
template <typename T>
|
||||
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<sol::table>())
|
||||
{
|
||||
@ -439,23 +445,24 @@ int lua_engine::enumerate_functions(const char *id, std::function<bool(const sol
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
});
|
||||
size_t count = enumerate_functions(
|
||||
id,
|
||||
[] (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;
|
||||
}
|
||||
|
||||
@ -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<bool>())
|
||||
{
|
||||
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<bool>())
|
||||
{
|
||||
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<sol::object>(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<const uint8_t *>(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<uint8_t *>(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<const uint8_t *>(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<sol::object>(s);
|
||||
|
||||
luaL_Buffer buff;
|
||||
uint8_t *dest = reinterpret_cast<uint8_t *>(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<const uint8_t *>(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<running_machine>("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<const char *> 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_t>("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 *(device_t::*)(std::string_view) const>(&device_t::subdevice);
|
||||
device_type["siblingdevice"] = static_cast<device_t *(device_t::*)(std::string_view) const>(&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 *(device_t::*)(std::string_view) const>(&device_t::subdevice));
|
||||
device_type.set_function("siblingdevice", static_cast<device_t *(device_t::*)(std::string_view) const>(&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<sol::protected_function>());
|
||||
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());
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ class lua_engine
|
||||
{
|
||||
public:
|
||||
// helper structures
|
||||
class buffer_helper;
|
||||
template <typename T> struct devenum;
|
||||
template <typename T> struct simple_list_wrapper;
|
||||
template <typename T> 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<typename T, size_t SIZE> class enum_parser;
|
||||
template <typename Func, typename... Params>
|
||||
static std::decay_t<std::invoke_result_t<Func, Params...> > invoke(Func &&func, Params&&... args)
|
||||
{
|
||||
g_profiler.start(PROFILER_LUA);
|
||||
try
|
||||
{
|
||||
auto result = func(std::forward<Params>(args)...);
|
||||
g_profiler.stop();
|
||||
return result;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
g_profiler.stop();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, size_t Size> 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<bool(const sol::protected_function &func)> &&callback);
|
||||
template <typename T> 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 <typename TFunc, typename... TArgs>
|
||||
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);
|
||||
|
@ -21,6 +21,24 @@
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct lua_engine::simple_list_wrapper
|
||||
{
|
||||
simple_list_wrapper(simple_list<T> const &l) : list(l) { }
|
||||
|
||||
simple_list<T> const &list;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
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 <typename T>
|
||||
struct lua_engine::simple_list_wrapper
|
||||
{
|
||||
simple_list_wrapper(simple_list<T> const &l) : list(l) { }
|
||||
|
||||
simple_list<T> const &list;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
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 <typename T, size_t SIZE>
|
||||
template <typename T, size_t Size>
|
||||
class lua_engine::enum_parser
|
||||
{
|
||||
public:
|
||||
constexpr enum_parser(std::initializer_list<std::pair<std::string_view, T> > 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<std::pair<std::string_view, T>, SIZE> m_map;
|
||||
std::array<std::pair<std::string_view, T>, Size> m_map;
|
||||
};
|
||||
|
||||
|
||||
@ -527,7 +527,7 @@ template <typename R, typename T, typename D>
|
||||
auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&), 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<R ()> &&
|
||||
else if (cb.is<sol::protected_function>())
|
||||
{
|
||||
(self.*setter)(delegate<R ()>(
|
||||
[this, dflt, desc, cbfunc = cb.as<sol::protected_function>()] () -> R
|
||||
[dflt, desc, cbfunc = cb.as<sol::protected_function>()] () -> R
|
||||
{
|
||||
if constexpr (std::is_same_v<R, void>)
|
||||
{
|
||||
@ -566,18 +566,4 @@ auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// invoke - invokes a function, wrapping profiler
|
||||
//-------------------------------------------------
|
||||
|
||||
template <typename TFunc, typename... TArgs>
|
||||
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<TArgs>(args)...);
|
||||
g_profiler.stop();
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // MAME_FRONTEND_MAME_LUAENGINE_IPP
|
||||
|
@ -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<sol::protected_function> setter, std::optional<char const *> format) -> symbol_entry &
|
||||
auto const do_add_symbol = [] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, std::optional<sol::protected_function> setter, std::optional<char const *> 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<sol::optional<u64> >();
|
||||
if (result)
|
||||
@ -217,12 +217,12 @@ void lua_engine::initialize_debug(sol::table &emu)
|
||||
[] (device_t &device)
|
||||
{ return std::make_shared<symbol_table_wrapper>(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<sol::protected_function>())
|
||||
st.table().set_memory_modified_func([this, cbfunc = cb.as<sol::protected_function>()] () { invoke(cbfunc); });
|
||||
st.table().set_memory_modified_func([cbfunc = cb.as<sol::protected_function>()] () { 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<sol::optional<u64> >();
|
||||
traceback.pop();
|
||||
return result ? *result : 0;
|
||||
|
@ -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<sol::optional<T> >();
|
||||
auto result = invoke(m_callback, offset, data, mem_mask).template get<sol::optional<T> >();
|
||||
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<sol::optional<T> >();
|
||||
auto result = invoke(m_callback, offset, data, mem_mask).template get<sol::optional<T> >();
|
||||
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>("addr_space", sol::no_constructor);
|
||||
addr_space_type["read_i8"] = &addr_space::mem_read<s8>;
|
||||
addr_space_type["read_u8"] = &addr_space::mem_read<u8>;
|
||||
addr_space_type["read_i16"] = &addr_space::mem_read<s16>;
|
||||
addr_space_type["read_u16"] = &addr_space::mem_read<u16>;
|
||||
addr_space_type["read_i32"] = &addr_space::mem_read<s32>;
|
||||
addr_space_type["read_u32"] = &addr_space::mem_read<u32>;
|
||||
addr_space_type["read_i64"] = &addr_space::mem_read<s64>;
|
||||
addr_space_type["read_u64"] = &addr_space::mem_read<u64>;
|
||||
addr_space_type["write_i8"] = &addr_space::mem_write<s8>;
|
||||
addr_space_type["write_u8"] = &addr_space::mem_write<u8>;
|
||||
addr_space_type["write_i16"] = &addr_space::mem_write<s16>;
|
||||
addr_space_type["write_u16"] = &addr_space::mem_write<u16>;
|
||||
addr_space_type["write_i32"] = &addr_space::mem_write<s32>;
|
||||
addr_space_type["write_u32"] = &addr_space::mem_write<u32>;
|
||||
addr_space_type["write_i64"] = &addr_space::mem_write<s64>;
|
||||
addr_space_type["write_u64"] = &addr_space::mem_write<u64>;
|
||||
addr_space_type["readv_i8"] = &addr_space::log_mem_read<s8>;
|
||||
addr_space_type["readv_u8"] = &addr_space::log_mem_read<u8>;
|
||||
addr_space_type["readv_i16"] = &addr_space::log_mem_read<s16>;
|
||||
addr_space_type["readv_u16"] = &addr_space::log_mem_read<u16>;
|
||||
addr_space_type["readv_i32"] = &addr_space::log_mem_read<s32>;
|
||||
addr_space_type["readv_u32"] = &addr_space::log_mem_read<u32>;
|
||||
addr_space_type["readv_i64"] = &addr_space::log_mem_read<s64>;
|
||||
addr_space_type["readv_u64"] = &addr_space::log_mem_read<u64>;
|
||||
addr_space_type["writev_i8"] = &addr_space::log_mem_write<s8>;
|
||||
addr_space_type["writev_u8"] = &addr_space::log_mem_write<u8>;
|
||||
addr_space_type["writev_i16"] = &addr_space::log_mem_write<s16>;
|
||||
addr_space_type["writev_u16"] = &addr_space::log_mem_write<u16>;
|
||||
addr_space_type["writev_i32"] = &addr_space::log_mem_write<s32>;
|
||||
addr_space_type["writev_u32"] = &addr_space::log_mem_write<u32>;
|
||||
addr_space_type["writev_i64"] = &addr_space::log_mem_write<s64>;
|
||||
addr_space_type["writev_u64"] = &addr_space::log_mem_write<u64>;
|
||||
addr_space_type["read_direct_i8"] = &addr_space::direct_mem_read<s8>;
|
||||
addr_space_type["read_direct_u8"] = &addr_space::direct_mem_read<u8>;
|
||||
addr_space_type["read_direct_i16"] = &addr_space::direct_mem_read<s16>;
|
||||
addr_space_type["read_direct_u16"] = &addr_space::direct_mem_read<u16>;
|
||||
addr_space_type["read_direct_i32"] = &addr_space::direct_mem_read<s32>;
|
||||
addr_space_type["read_direct_u32"] = &addr_space::direct_mem_read<u32>;
|
||||
addr_space_type["read_direct_i64"] = &addr_space::direct_mem_read<s64>;
|
||||
addr_space_type["read_direct_u64"] = &addr_space::direct_mem_read<u64>;
|
||||
addr_space_type["write_direct_i8"] = &addr_space::direct_mem_write<s8>;
|
||||
addr_space_type["write_direct_u8"] = &addr_space::direct_mem_write<u8>;
|
||||
addr_space_type["write_direct_i16"] = &addr_space::direct_mem_write<s16>;
|
||||
addr_space_type["write_direct_u16"] = &addr_space::direct_mem_write<u16>;
|
||||
addr_space_type["write_direct_i32"] = &addr_space::direct_mem_write<s32>;
|
||||
addr_space_type["write_direct_u32"] = &addr_space::direct_mem_write<u32>;
|
||||
addr_space_type["write_direct_i64"] = &addr_space::direct_mem_write<s64>;
|
||||
addr_space_type["write_direct_u64"] = &addr_space::direct_mem_write<u64>;
|
||||
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<s8>);
|
||||
addr_space_type.set_function("read_u8", &addr_space::mem_read<u8>);
|
||||
addr_space_type.set_function("read_i16", &addr_space::mem_read<s16>);
|
||||
addr_space_type.set_function("read_u16", &addr_space::mem_read<u16>);
|
||||
addr_space_type.set_function("read_i32", &addr_space::mem_read<s32>);
|
||||
addr_space_type.set_function("read_u32", &addr_space::mem_read<u32>);
|
||||
addr_space_type.set_function("read_i64", &addr_space::mem_read<s64>);
|
||||
addr_space_type.set_function("read_u64", &addr_space::mem_read<u64>);
|
||||
addr_space_type.set_function("write_i8", &addr_space::mem_write<s8>);
|
||||
addr_space_type.set_function("write_u8", &addr_space::mem_write<u8>);
|
||||
addr_space_type.set_function("write_i16", &addr_space::mem_write<s16>);
|
||||
addr_space_type.set_function("write_u16", &addr_space::mem_write<u16>);
|
||||
addr_space_type.set_function("write_i32", &addr_space::mem_write<s32>);
|
||||
addr_space_type.set_function("write_u32", &addr_space::mem_write<u32>);
|
||||
addr_space_type.set_function("write_i64", &addr_space::mem_write<s64>);
|
||||
addr_space_type.set_function("write_u64", &addr_space::mem_write<u64>);
|
||||
addr_space_type.set_function("readv_i8", &addr_space::log_mem_read<s8>);
|
||||
addr_space_type.set_function("readv_u8", &addr_space::log_mem_read<u8>);
|
||||
addr_space_type.set_function("readv_i16", &addr_space::log_mem_read<s16>);
|
||||
addr_space_type.set_function("readv_u16", &addr_space::log_mem_read<u16>);
|
||||
addr_space_type.set_function("readv_i32", &addr_space::log_mem_read<s32>);
|
||||
addr_space_type.set_function("readv_u32", &addr_space::log_mem_read<u32>);
|
||||
addr_space_type.set_function("readv_i64", &addr_space::log_mem_read<s64>);
|
||||
addr_space_type.set_function("readv_u64", &addr_space::log_mem_read<u64>);
|
||||
addr_space_type.set_function("writev_i8", &addr_space::log_mem_write<s8>);
|
||||
addr_space_type.set_function("writev_u8", &addr_space::log_mem_write<u8>);
|
||||
addr_space_type.set_function("writev_i16", &addr_space::log_mem_write<s16>);
|
||||
addr_space_type.set_function("writev_u16", &addr_space::log_mem_write<u16>);
|
||||
addr_space_type.set_function("writev_i32", &addr_space::log_mem_write<s32>);
|
||||
addr_space_type.set_function("writev_u32", &addr_space::log_mem_write<u32>);
|
||||
addr_space_type.set_function("writev_i64", &addr_space::log_mem_write<s64>);
|
||||
addr_space_type.set_function("writev_u64", &addr_space::log_mem_write<u64>);
|
||||
addr_space_type.set_function("read_direct_i8", &addr_space::direct_mem_read<s8>);
|
||||
addr_space_type.set_function("read_direct_u8", &addr_space::direct_mem_read<u8>);
|
||||
addr_space_type.set_function("read_direct_i16", &addr_space::direct_mem_read<s16>);
|
||||
addr_space_type.set_function("read_direct_u16", &addr_space::direct_mem_read<u16>);
|
||||
addr_space_type.set_function("read_direct_i32", &addr_space::direct_mem_read<s32>);
|
||||
addr_space_type.set_function("read_direct_u32", &addr_space::direct_mem_read<u32>);
|
||||
addr_space_type.set_function("read_direct_i64", &addr_space::direct_mem_read<s64>);
|
||||
addr_space_type.set_function("read_direct_u64", &addr_space::direct_mem_read<u64>);
|
||||
addr_space_type.set_function("write_direct_i8", &addr_space::direct_mem_write<s8>);
|
||||
addr_space_type.set_function("write_direct_u8", &addr_space::direct_mem_write<u8>);
|
||||
addr_space_type.set_function("write_direct_i16", &addr_space::direct_mem_write<s16>);
|
||||
addr_space_type.set_function("write_direct_u16", &addr_space::direct_mem_write<u16>);
|
||||
addr_space_type.set_function("write_direct_i32", &addr_space::direct_mem_write<s32>);
|
||||
addr_space_type.set_function("write_direct_u32", &addr_space::direct_mem_write<u32>);
|
||||
addr_space_type.set_function("write_direct_i64", &addr_space::direct_mem_write<s64>);
|
||||
addr_space_type.set_function("write_direct_u64", &addr_space::direct_mem_write<u64>);
|
||||
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<u64>())
|
||||
{
|
||||
step = opt_step.as<u64>();
|
||||
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<u8>(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<u16>(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<u32>(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<u64>(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<tap_helper>(*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<tap_helper>(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<tap_helper>(*this, sp.space, read_or_write::WRITE, start, end, std::move(name), std::move(cb));
|
||||
};
|
||||
return std::make_unique<tap_helper>(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<tap_helper>("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<memory_region>("region", sol::no_constructor);
|
||||
region_type["read_i8"] = ®ion_read<s8>;
|
||||
region_type["read_u8"] = ®ion_read<u8>;
|
||||
region_type["read_i16"] = ®ion_read<s16>;
|
||||
region_type["read_u16"] = ®ion_read<u16>;
|
||||
region_type["read_i32"] = ®ion_read<s32>;
|
||||
region_type["read_u32"] = ®ion_read<u32>;
|
||||
region_type["read_i64"] = ®ion_read<s64>;
|
||||
region_type["read_u64"] = ®ion_read<u64>;
|
||||
region_type["write_i8"] = ®ion_write<s8>;
|
||||
region_type["write_u8"] = ®ion_write<u8>;
|
||||
region_type["write_i16"] = ®ion_write<s16>;
|
||||
region_type["write_u16"] = ®ion_write<u16>;
|
||||
region_type["write_i32"] = ®ion_write<s32>;
|
||||
region_type["write_u32"] = ®ion_write<u32>;
|
||||
region_type["write_i64"] = ®ion_write<s64>;
|
||||
region_type["write_u64"] = ®ion_write<u64>;
|
||||
region_type.set_function("read_i8", ®ion_read<s8>);
|
||||
region_type.set_function("read_u8", ®ion_read<u8>);
|
||||
region_type.set_function("read_i16", ®ion_read<s16>);
|
||||
region_type.set_function("read_u16", ®ion_read<u16>);
|
||||
region_type.set_function("read_i32", ®ion_read<s32>);
|
||||
region_type.set_function("read_u32", ®ion_read<u32>);
|
||||
region_type.set_function("read_i64", ®ion_read<s64>);
|
||||
region_type.set_function("read_u64", ®ion_read<u64>);
|
||||
region_type.set_function("write_i8", ®ion_write<s8>);
|
||||
region_type.set_function("write_u8", ®ion_write<u8>);
|
||||
region_type.set_function("write_i16", ®ion_write<s16>);
|
||||
region_type.set_function("write_u16", ®ion_write<u16>);
|
||||
region_type.set_function("write_i32", ®ion_write<s32>);
|
||||
region_type.set_function("write_u32", ®ion_write<u32>);
|
||||
region_type.set_function("write_i64", ®ion_write<s64>);
|
||||
region_type.set_function("write_u64", ®ion_write<u64>);
|
||||
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<memory_share>("share", sol::no_constructor);
|
||||
share_type["read_i8"] = &share_read<s8>;
|
||||
share_type["read_u8"] = &share_read<u8>;
|
||||
share_type["read_i16"] = &share_read<s16>;
|
||||
share_type["read_u16"] = &share_read<u16>;
|
||||
share_type["read_i32"] = &share_read<s32>;
|
||||
share_type["read_u32"] = &share_read<u32>;
|
||||
share_type["read_i64"] = &share_read<s64>;
|
||||
share_type["read_u64"] = &share_read<u64>;
|
||||
share_type["write_i8"] = &share_write<s8>;
|
||||
share_type["write_u8"] = &share_write<u8>;
|
||||
share_type["write_i16"] = &share_write<s16>;
|
||||
share_type["write_u16"] = &share_write<u16>;
|
||||
share_type["write_i32"] = &share_write<s32>;
|
||||
share_type["write_u32"] = &share_write<u32>;
|
||||
share_type["write_i64"] = &share_write<s64>;
|
||||
share_type["write_u64"] = &share_write<u64>;
|
||||
share_type.set_function("read_i8", &share_read<s8>);
|
||||
share_type.set_function("read_u8", &share_read<u8>);
|
||||
share_type.set_function("read_i16", &share_read<s16>);
|
||||
share_type.set_function("read_u16", &share_read<u16>);
|
||||
share_type.set_function("read_i32", &share_read<s32>);
|
||||
share_type.set_function("read_u32", &share_read<u32>);
|
||||
share_type.set_function("read_i64", &share_read<s64>);
|
||||
share_type.set_function("read_u64", &share_read<u64>);
|
||||
share_type.set_function("write_i8", &share_write<s8>);
|
||||
share_type.set_function("write_u8", &share_write<u8>);
|
||||
share_type.set_function("write_i16", &share_write<s16>);
|
||||
share_type.set_function("write_u16", &share_write<u16>);
|
||||
share_type.set_function("write_i32", &share_write<s32>);
|
||||
share_type.set_function("write_u32", &share_write<u32>);
|
||||
share_type.set_function("write_i64", &share_write<s64>);
|
||||
share_type.set_function("write_u64", &share_write<u64>);
|
||||
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(); });
|
||||
|
@ -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<inifile_manager>(m_ui->options());
|
||||
@ -347,6 +382,25 @@ void mame_machine_manager::create_custom(running_machine& machine)
|
||||
|
||||
// start favorite manager
|
||||
m_favorite = std::make_unique<favorite_manager>(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)
|
||||
|
@ -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<plugin_options> m_plugins; // pointer to plugin options
|
||||
std::unique_ptr<lua_engine> m_lua;
|
||||
std::unique_ptr<plugin_options> m_plugins; // pointer to plugin options
|
||||
std::unique_ptr<lua_engine> 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<mame_ui_manager> m_ui; // internal data from ui.cpp
|
||||
std::unique_ptr<cheat_manager> m_cheat; // internal data from cheat.cpp
|
||||
std::unique_ptr<inifile_manager> m_inifile; // internal data from inifile.c for INIs
|
||||
std::unique_ptr<favorite_manager> m_favorite; // internal data from inifile.c for favorites
|
||||
emu_timer * m_autoboot_timer; // auto-boot timer
|
||||
std::unique_ptr<sol::load_result> m_autoboot_script; // auto-boot script
|
||||
std::unique_ptr<mame_ui_manager> m_ui; // internal data from ui.cpp
|
||||
std::unique_ptr<cheat_manager> m_cheat; // internal data from cheat.cpp
|
||||
std::unique_ptr<inifile_manager> m_inifile; // internal data from inifile.c for INIs
|
||||
std::unique_ptr<favorite_manager> m_favorite; // internal data from inifile.c for favorites
|
||||
|
||||
static mame_machine_manager *s_manager;
|
||||
};
|
||||
|
||||
//**************************************************************************
|
||||
|
Loading…
Reference in New Issue
Block a user