diff options
Diffstat (limited to 'src/frontend/mame/luaengine.cpp')
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 275 |
1 files changed, 143 insertions, 132 deletions
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<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()); } |