CC-Tweaked/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua

113 lines
3.4 KiB
Lua

--- The commands API allows your system to directly execute [Minecraft
-- commands][mc] and gather data from the results.
--
-- While one may use @{commands.exec} directly to execute a command, the
-- commands API also provides helper methods to execute every command. For
-- instance, `commands.say("Hi!")` is equivalent to `commands.exec("say Hi!")`.
--
-- @{commands.async} provides a similar interface to execute asynchronous
-- commands. `commands.async.say("Hi!")` is equivalent to
-- `commands.execAsync("Hi!")`.
--
-- [mc]: https://minecraft.gamepedia.com/Commands
--
-- @module commands
-- @usage Set the block above this computer to stone:
--
-- commands.setblock("~", "~1", "~", "minecraft:stone")
if not commands then
error("Cannot load command API on normal computer", 2)
end
--- The builtin commands API, without any generated command helper functions
--
-- This may be useful if a built-in function (such as @{commands.list}) has been
-- overwritten by a command.
local native = commands.native or commands
local function collapseArgs(bJSONIsNBT, ...)
local args = table.pack(...)
for i = 1, #args do
local arg = args[i]
if type(arg) == "boolean" or type(arg) == "number" or type(arg) == "string" then
args[i] = tostring(arg)
elseif type(arg) == "table" then
args[i] = textutils.serialiseJSON(arg, bJSONIsNBT)
else
error("Expected string, number, boolean or table", 3)
end
end
return table.concat(args, " ")
end
-- Put native functions into the environment
local env = _ENV
env.native = native
for k, v in pairs(native) do
env[k] = v
end
-- Create wrapper functions for all the commands
local tAsync = {}
local tNonNBTJSONCommands = {
["tellraw"] = true,
["title"] = true,
}
local command_mt = {}
function command_mt.__call(self, ...)
local meta = self[command_mt]
local sCommand = collapseArgs(meta.json, table.concat(meta.name, " "), ...)
return meta.func(sCommand)
end
function command_mt.__tostring(self)
local meta = self[command_mt]
return ("command %q"):format("/" .. table.concat(meta.name, " "))
end
local function mk_command(name, json, func)
return setmetatable({
[command_mt] = {
name = name,
func = func,
json = json,
},
}, command_mt)
end
function command_mt.__index(self, key)
local meta = self[command_mt]
if meta.children then return nil end
meta.children = true
local name = meta.name
for _, child in ipairs(native.list(table.unpack(name))) do
local child_name = { table.unpack(name) }
child_name[#child_name + 1] = child
self[child] = mk_command(child_name, meta.json, meta.func)
end
return self[key]
end
for _, sCommandName in ipairs(native.list()) do
if env[sCommandName] == nil then
local bJSONIsNBT = tNonNBTJSONCommands[sCommandName] == nil
env[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.exec)
tAsync[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.execAsync)
end
end
--- A table containing asynchronous wrappers for all commands.
--
-- As with @{commands.execAsync}, this returns the "task id" of the enqueued
-- command.
-- @see execAsync
-- @usage Asynchronously sets the block above the computer to stone.
--
-- commands.async.setblock("~", "~1", "~", "minecraft:stone")
env.async = tAsync