Files
ReSkate/Extension/Plugins/plugin_commands.cpp
T
AyeZeeBB 6d542536e1 Plugins: sandboxed Luau plugins in mods, phase 1 (the host, and the base, console and storage APIs)
A mod with a reskate-plugin.json is a plugin: Luau scripts that run in their own VM, with only
the reskate API ReSkate registers for them. Luau 0.741 is vendored in External/luau (the VM and
compiler only: no native code generation, no loadstring, io or C modules).

- Limits: 64 MB of memory, 50 ms a call, 2 ms a tick on average (over it for 3 s stops it),
  more than 5 errors in 10 s stops it, 50 log lines a second. A plugin over a limit cannot catch
  it in a pcall and carry on.
- API: reskate.log, on (load, unload, tick, level_loaded, level_unloading), timers, the level,
  its own package's files and JSON, require inside the package; console.command and print
  ("console"); storage get, set, add and keys ("storage"), 1 MB in
  %LOCALAPPDATA%\ReSkate\Plugins\<mod>\storage.json.
- Found every 2 s among the mods mods.json leaves on: switching a mod, or changing a plugin's
  files, loads, unloads or reloads it without a restart. A package holding a program is refused.
- plugin list, commands, reload, off and on in the console. A plugin cannot take a name of
  ReSkate's own commands.
- Tests: DINGOSDK_BUILD_PLUGIN_TESTS, including plugins written to break the sandbox.
2026-10-19 11:55:27 -05:00

41 lines
2.1 KiB
C++

#include "plugin_runtime.h"
#include "Extension/Console/commands.h"
// `plugin list`, `plugin commands`, `plugin reload|off|on <id>`: the plugins' state, and a
// plugin restarted or switched off by hand without touching its mod.
namespace dingosdk::console {
namespace {
void write_lines(const Output& out, const std::string& text) {
std::size_t start = 0;
while (start <= text.size()) {
const auto end = std::min(text.find('\n', start), text.size());
out(text.substr(start, end - start));
start = end + 1;
}
}
// No completion of ids: completion may run off the client thread, which alone reads the plugins.
Argument plugin_id() { return argument("id"); }
}
void register_plugin_commands(Commands& registry) {
auto list = action("plugin list", "List the plugins: running, stopped and why, memory and time a tick", Group::console);
list.run = [](const Model&, const Values&, const Output& out) { write_lines(out, plugins::describe()); };
registry.add(std::move(list));
auto commands = action("plugin commands", "List the console commands plugins added", Group::console);
commands.run = [](const Model&, const Values&, const Output& out) { write_lines(out, plugins::list_commands()); };
registry.add(std::move(commands));
auto reload = action("plugin reload", "Unload a plugin and load it again from its files", Group::console, {plugin_id()});
reload.run = [](const Model&, const Values& args, const Output& out) { out(plugins::reload(std::get<std::string>(args[0]))); };
registry.add(std::move(reload));
auto off = action("plugin off", "Switch a plugin off until plugin on, or the next launch", Group::console, {plugin_id()});
off.run = [](const Model&, const Values& args, const Output& out) { out(plugins::switch_off(std::get<std::string>(args[0]))); };
registry.add(std::move(off));
auto on = action("plugin on", "Start a plugin that was switched off or stopped", Group::console, {plugin_id()});
on.run = [](const Model&, const Values& args, const Output& out) { out(plugins::switch_on(std::get<std::string>(args[0]))); };
registry.add(std::move(on));
}
} // namespace dingosdk::console