From 9a8a4dea19f6b74fd7503a1b73599d11c849fc37 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Thu, 24 Jan 2019 23:11:19 -0800 Subject: [PATCH 1/9] Tweak README Horizontal rules are weird sometimes. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 508f9f8..72e96d7 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ To install Allium, run this command, it's that simple! `pastebin run LGwrkjxm` -The installer installs Apemanzilla's [gitget](http://www.computercraft.info/forums2/index.php?/topic/17387-gitget-version-2-release/), a github repository downloader that is necessary to download the bot, and the plugins that can be installed. +The installer installs Apemanzilla's [gitget](http://www.computercraft.info/forums2/index.php?/topic/17387-gitget-version-2-release/), a github repository downloader that is necessary to download Allium, and the plugins that can be installed. ## Base Commands `!help`: Lists the info entries for the installed plugins @@ -136,6 +136,7 @@ l - bold m - strikethrough n - italic o - underline + --- ## Cloning this repository It's worth noting that there are some places you might want to check out after you fork, and before you start testing your code. From d751db4bda0ca0b5a2694f08819f77c2001e4cc1 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Thu, 24 Jan 2019 23:23:52 -0800 Subject: [PATCH 2/9] Redefine meaning of JSON - persistence.json wasn't actually JSON, but rather just a serialized table. Naturally, the file has been renamed to persistence.ltn, standing for Lua Table Notation. - Readme has been tweaked so that color codes aren't all mushed up --- .gitignore | 2 +- README.md | 52 ++++++++++++++++++++++++++-------------------------- allium.lua | 14 +++++++------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index aa50e87..983bd14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ repolist.csh -persistence.json +persistence.ltn gitget.lua json \ No newline at end of file diff --git a/README.md b/README.md index 72e96d7..137f448 100644 --- a/README.md +++ b/README.md @@ -106,36 +106,36 @@ Quick reference for plugin developers: The following characters are all valid for formatting in `allium.tell` when prefixxed with an `&`. ### Colors -r - reset formatting -0 - black -1 - dark blue -2 - dark green -3 - dark aqua -4 - dark red -5 - dark purple -6 - gold -7 - gray -8 - dark gray -9 - blue -a - green -b - aqua -c - red -d - light purple -e - yellow -f - white +- r - reset formatting +- 0 - black +- 1 - dark blue +- 2 - dark green +- 3 - dark aqua +- 4 - dark red +- 5 - dark purple +- 6 - gold +- 7 - gray +- 8 - dark gray +- 9 - blue +- a - green +- b - aqua +- c - red +- d - light purple +- e - yellow +- f - white ### Actions -g - execute text | `&g(!allium:help)Click for help!&r` -h - hover text | `&h(Hi there :P)Mouse over me!&r` -i - clickable link | `&i(https://google.com)Go to google!&r` -s - suggest text | `&s(I'm in your bar now!)Click on me!&r` +- g - execute text | `&g(!allium:help)Click for help!&r` +- h - hover text | `&h(Hi there :P)Mouse over me!&r` +- i - clickable link | `&i(https://google.com)Go to google!&r` +- s - suggest text | `&s(I'm in your bar now!)Click on me!&r` ### Emphases -k - obfuscated -l - bold -m - strikethrough -n - italic -o - underline +- k - obfuscated +- l - bold +- m - strikethrough +- n - italic +- o - underline --- ## Cloning this repository diff --git a/allium.lua b/allium.lua index ae6c238..aad3600 100644 --- a/allium.lua +++ b/allium.lua @@ -122,8 +122,8 @@ allium.register = function(p_name, fullname) end funcs.getPersistence = function(name) - if fs.exists("persistence.json") then - local fper = fs.open("persistence.json", "r") + if fs.exists("persistence.ltn") then + local fper = fs.open("persistence.ltn", "r") local tpersist = textutils.unserialize(fper.readAll()) fper.close() if not tpersist[p_name] then @@ -138,8 +138,8 @@ allium.register = function(p_name, fullname) funcs.setPersistence = function(name, data) local tpersist - if fs.exists("persistence.json") then - local fper = fs.open("persistence.json", "r") + if fs.exists("persistence.ltn") then + local fper = fs.open("persistence.ltn", "r") tpersist = textutils.unserialize(fper.readAll()) fper.close() end @@ -148,7 +148,7 @@ allium.register = function(p_name, fullname) end if type(name) == "string" then tpersist[p_name][name] = data - local fpers = fs.open("persistence.json", "w") + local fpers = fs.open("persistence.ltn", "w") fpers.write(textutils.serialise(tpersist)) fpers.close() return true @@ -253,8 +253,8 @@ end raisin.thread.add(main, 0) -if not fs.exists("persistence.json") then --In the situation that this is a first installation, let's add persistence.json - local fpers = fs.open("persistence.json", "w") +if not fs.exists("persistence.ltn") then --In the situation that this is a first installation, let's add persistence.ltn + local fpers = fs.open("persistence.ltn", "w") fpers.write("{}") fpers.close() end From 2e2fd830ff40d48e32cdfcca1a3863fb04ddd3ad Mon Sep 17 00:00:00 2001 From: hugeblank Date: Thu, 24 Jan 2019 23:45:15 -0800 Subject: [PATCH 3/9] Include Installer information in README --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 137f448..6be605d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,19 @@ To install Allium, run this command, it's that simple! `pastebin run LGwrkjxm` -The installer installs Apemanzilla's [gitget](http://www.computercraft.info/forums2/index.php?/topic/17387-gitget-version-2-release/), a github repository downloader that is necessary to download Allium, and the plugins that can be installed. +The installer installs: + +- The Allium repo - allium.lua, plugins/allium-stem.lua, colors.lua, readme.md + +- The Raisin Repo - raisin/raisin.lua, raisin/readme.md + +- Apemanzilla's [gitget](http://www.computercraft.info/forums2/index.php?/topic/17387-gitget-version-2-release/), a github repository downloader that is necessary to download Allium, and the plugins that can be installed. + +- repolist.csh - A _Craftos SHell_ file, where you can gitget various plugins and utilities and keep them up to date. + +- startup.lua - startup file that runs the repolist file, then runs Allium. When Allium crashes/exits it will reboot after 3 seconds unless interrupted. + +- persistence.ltn - A _Lua Table Notation_ file containing all serialized persistence entries for each plugin. ## Base Commands `!help`: Lists the info entries for the installed plugins @@ -141,5 +153,5 @@ The following characters are all valid for formatting in `allium.tell` when pref ## Cloning this repository It's worth noting that there are some places you might want to check out after you fork, and before you start testing your code. -1. The pastebin [installer](https://www.pastebin.com/LGwrkjxm). You are free to make your own installer to your fork with this code, simply change the `repo` string to "your github username"/"the name of your Allium repository". +1. The pastebin [installer](https://www.pastebin.com/LGwrkjxm). You are free to make your own installer to your fork with this code, simply change the `repo` string to "[your github username] [the name of your Allium repository] [the branch you want to clone from] [location]". 2. The startup file of your fork. There is a line that has a comment along with it. Change that repo name from the official Allium repository to your forked repository, similar to the style shown above. \ No newline at end of file From 0f8157a89f6702486c735ec892bf7675762c35ce Mon Sep 17 00:00:00 2001 From: hugeblank Date: Sun, 27 Jan 2019 03:22:22 -0800 Subject: [PATCH 4/9] Various tweaks - Updated Allium side image - Text now wraps before clipping over allium logo - Made allium.assert more useful by defaulting error level to 3 - Integrating latest version of Raisin - Tweaked naming convention of data passed into command on execution - Updated allium-stem to incorporate aforementioned tweaks. - Removed mysterious comment lurking in allium-stem, from a past life - Updated readme to include some major details, and clear up minor typos - Tweaked get/setPersistence to use plugin IDs instead of full names - Changed the startup delay from 3 to 5 seconds - And other more minor tweaks that aren't worth mentioning --- README.md | 30 +++++++++++--- allium.lua | 89 +++++++++++++++++++++-------------------- allium.nfp | 2 +- plugins/allium-stem.lua | 28 +------------ raisin | 2 +- startup.lua | 4 +- 6 files changed, 75 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 6be605d..82981fc 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ To install Allium, run this command, it's that simple! The installer installs: -- The Allium repo - allium.lua, plugins/allium-stem.lua, colors.lua, readme.md +- The Allium Repo - allium.lua, plugins/allium-stem.lua, colors.lua, readme.md - The Raisin Repo - raisin/raisin.lua, raisin/readme.md @@ -27,7 +27,9 @@ The installer installs: - persistence.ltn - A _Lua Table Notation_ file containing all serialized persistence entries for each plugin. -## Base Commands +## Stem Commands +These are the commands that make up the backbone of Allium, the stem per se. + `!help`: Lists the info entries for the installed plugins `!plugins`: Lists the plugins that are installed, based on the name of the directory that they're found in. @@ -37,7 +39,8 @@ The installer installs: ## API Quick reference for plugin developers: -### `allium`: +### `allium` +#### Methods: `assert`: Lua's generic assert, with the ability to set the error level - **Parameters** - _boolean_: condition to test @@ -84,8 +87,11 @@ Quick reference for plugin developers: - _[string]_: optional manually set human readable plugin name - **Returns** - _table_: list of functions to register commands/threads/persistent data (see below) +#### Other: +_string_ `side`: The location of the chat recorder that allium is using -### `register`: +### `allium.register` +#### Methods: `command`: Register a command within this plugin - **Parameters** - _string_: command name @@ -114,8 +120,20 @@ Quick reference for plugin developers: - **Returns** - _any_: data that was assigned to that value --- +## Command Data + Information on what is given to a command on invocation: + - _string_: name of the user that invoked the command + - _table_: arguments provided after the invocation (Eg: `!help allium 2` args: `{"allium", "2"}`) + - _table_: list of infrequently used, but useful utilities + - `error` _function_ | Quick and easy way to return command usage, or other information to the executor + - **Parameters** + - _[string]_: error message, if left nil uses the command usage string + - **Returns** + - _none_ + - `usage` _string_ | Provides raw access to the usage string for the command +--- ## Formatting Codes -The following characters are all valid for formatting in `allium.tell` when prefixxed with an `&`. +The following characters are all valid for formatting in `allium.tell` when prefixxed with an `&`: ### Colors - r - reset formatting @@ -150,7 +168,7 @@ The following characters are all valid for formatting in `allium.tell` when pref - o - underline --- -## Cloning this repository +## Forking this repository It's worth noting that there are some places you might want to check out after you fork, and before you start testing your code. 1. The pastebin [installer](https://www.pastebin.com/LGwrkjxm). You are free to make your own installer to your fork with this code, simply change the `repo` string to "[your github username] [the name of your Allium repository] [the branch you want to clone from] [location]". diff --git a/allium.lua b/allium.lua index aad3600..6d288eb 100644 --- a/allium.lua +++ b/allium.lua @@ -1,5 +1,10 @@ -- Allium by hugeblank -paintutils.drawImage(paintutils.loadImage("allium.nfp"), 40, 2) -- Draw the Allium image on the side +do -- Allium image setup <3 + local x, y = term.getSize() + paintutils.drawImage(paintutils.loadImage("allium.nfp"), x-7, 2) -- Draw the Allium image on the side + local win = window.create(term.current(), 1, 1, x-9, y, true) + term.redirect(win) +end term.setBackgroundColor(colors.black) -- Reset terminal and cursor term.setTextColor(colors.white) term.setCursorPos(1, 1) @@ -7,34 +12,31 @@ term.setCursorPos(1, 1) print("Loading Allium") print("Initializing API") -local mName = "<&r&dAll&5&h(Hugeblank was here. Hi.)&i(https://www.youtube.com/watch?v=PomZJao7Raw)i&r&dum&r>" --bot title -local raisin = require("raisin.raisin") -local color = require("color") --Sponsored by roger109z +local label = "<&r&dAll&5&h(Hugeblank was here. Hi.)&i(https://www.youtube.com/watch?v=PomZJao7Raw)i&r&dum&r>" --bot title +local raisin, color = require("raisin.raisin"), require("color") --Sponsored by roger109z local allium = {} -- API table -local group = {thread = raisin.group.add(1), command = raisin.group.add(2)} +local group = {thread = raisin.group.add(1) , command = raisin.group.add(2)} -- threads first, commands second, plugin groups third local plugins = {} -- Plugin table allium.assert = function(condition, message, level) - if not condition then error(message, level) end + if not condition then error(message, level or 3) end end local assert = allium.assert allium.sanitize = function(name) - if name then - return name:lower():gsub(" ", "-") - end + assert(type(name) == "string", "Invalid argument #1 (expected string, got "..type(name)..")") + return name:lower():gsub(" ", "-") end -allium.tell = function(name, message, botname) --allium.tell as documented in README - if not (type(message) == "string" or type(message) == "table") then - return false - end +allium.tell = function(name, message, alt_name) + assert(type(name) == "string", "Invalid argument #1 (expected string, got "..type(name)..")") + assert(type(message) == "string" or type(message) == "table", "Invalid argument #2 (expected string or table, got "..type(message)..")") local test if type(message) == "table" then _, test = commands.tellraw(name, color.format(table.concat(message, "\n"))) else - _, test = commands.tellraw(name, color.format((function(botname) if botname == true then return "" elseif botname then return botname.."&r " else return mName.."&r " end end)(botname)..message)) + _, test = commands.tellraw(name, color.format((function(alt_name) if alt_name == true then return "" elseif alt_name then return alt_name.."&r " else return label.."&r " end end)(alt_name)..message)) end return textutils.serialise(test) end @@ -43,7 +45,7 @@ allium.getPlayers = function() local didexec, input = commands.exec("list") local out = {} if not didexec then - local _, users = commands.testfor("@a") + local _, users = commands.exec("testfor @a") for i = 1, #users do out[#out+1] = string.sub(users[i], 7, -1) end @@ -93,61 +95,63 @@ allium.getInfo = function(plugin) -- Get the information of all plugins, or a si end allium.getName = function(plugin) - assert(type(plugin) == "string", "Invalid argument #1 (string expected, got "..type(plugin)..")", 3) + assert(type(plugin) == "string", "Invalid argument #1 (string expected, got "..type(plugin)..")") if plugins[plugin] then return plugins[plugin].name end end allium.register = function(p_name, fullname) - assert(type(p_name) == "string", "Invalid argument #1 (string expected, got "..type(p_name)..")", 3) + assert(type(p_name) == "string", "Invalid argument #1 (string expected, got "..type(p_name)..")") local real_name = allium.sanitize(p_name) - assert(plugins[real_name] == nil, "Invalid argument #1 (plugin exists under name "..real_name..")", 3) + assert(plugins[real_name] == nil, "Invalid argument #1 (plugin exists under name "..real_name..")") plugins[real_name] = {threads = {}, commands = {}, name = fullname or p_name} local funcs = {} local this = plugins[real_name] funcs.command = function(c_name, command, info, usage) -- name: name | command: executing function | info: help information | usage: string for improper inputs - assert(type(c_name) == "string", "Invalid argument #1 (string expected, got "..type(c_name)..")", 3) + assert(type(c_name) == "string", "Invalid argument #1 (string expected, got "..type(c_name)..")") local real_name = allium.sanitize(c_name) - assert(type(command) == "function", "Invalid argument #2 (function expected, got "..type(command)..")", 3) - assert(this.commands[real_name] == nil, "Invalid argument #2 (command exists under name "..real_name.." for plugin "..this.name..")", 3) - assert(type(info) == "string", "Invalid argument #3 (string expected, got "..type(info)..")", 3) + assert(type(command) == "function", "Invalid argument #2 (function expected, got "..type(command)..")") + assert(this.commands[real_name] == nil, "Invalid argument #2 (command exists under name "..real_name.." for plugin "..this.name..")") + assert(type(info) == "string", "Invalid argument #3 (string expected, got "..type(info)..")") this.commands[real_name] = {command = command, info = info, usage = usage} end funcs.thread = function(thread) - assert(type(thread) == "function", "Invalid argument #1 (function expected, got "..type(thread)..")", 3) - return raisin.thread.add(thread, 0, group.thread) + assert(type(thread) == "function", "Invalid argument #1 (function expected, got "..type(thread)..")") + raisin.thread.add(thread, 0, group.thread) end funcs.getPersistence = function(name) + assert(type(name) ~= "nil", "Invalid argument #1 (expected anything but nil, got "..type(name)..")") if fs.exists("persistence.ltn") then local fper = fs.open("persistence.ltn", "r") local tpersist = textutils.unserialize(fper.readAll()) fper.close() - if not tpersist[p_name] then - tpersist[p_name] = {} + if not tpersist[real_name] then + tpersist[real_name] = {} end if type(name) == "string" then - return tpersist[p_name][name] + return tpersist[real_name][name] end end return false end funcs.setPersistence = function(name, data) + assert(type(name) ~= "nil", "Invalid argument #1 (expected anything but nil, got "..type(name)..")") local tpersist if fs.exists("persistence.ltn") then local fper = fs.open("persistence.ltn", "r") tpersist = textutils.unserialize(fper.readAll()) fper.close() end - if not tpersist[p_name] then - tpersist[p_name] = {} + if not tpersist[real_name] then + tpersist[real_name] = {} end if type(name) == "string" then - tpersist[p_name][name] = data + tpersist[real_name][name] = data local fpers = fs.open("persistence.ltn", "w") fpers.write(textutils.serialise(tpersist)) fpers.close() @@ -159,8 +163,7 @@ allium.register = function(p_name, fullname) return funcs end --- Finding the chat module -for _, side in pairs(peripheral.getNames()) do +for _, side in pairs(peripheral.getNames()) do -- Finding the chat module if peripheral.getMethods(side) then for _, method in pairs(peripheral.getMethods(side)) do if method == "capture" then @@ -172,11 +175,7 @@ for _, side in pairs(peripheral.getNames()) do end if allium.side then break end end - -if not allium.side then - printError("Cannot find chat module") - return -end +assert(allium.side, "Allium requires a creative chat module in order to operate") _G.allium = allium -- Globalizing Allium API @@ -214,9 +213,9 @@ local main = function() local cmd_exec if not string.find(cmd, ":") then --did they not specify the plugin source? for p_name, plugin in pairs(plugins) do --nope... gonna have to find it for them. - for c_name, command in pairs(plugin.commands) do + for c_name, data in pairs(plugin.commands) do if c_name == cmd then --well I found it, but there may be more... - cmd_exec = {command = command, plugin = p_name} --split into command function, source + cmd_exec = {data = data, plugin = p_name, command = c_name} --split into command function, source break end end @@ -227,19 +226,21 @@ local main = function() local p_name, c_name = string.sub(cmd, 1, splitat-1), string.sub(cmd, splitat+1, -1) if plugins[p_name] then --check plugin existence if plugins[p_name].commands[c_name] then --check command existence - cmd_exec = {command = plugins[p_name].commands[c_name], plugin = p_name} --split it into the function, and then the source + cmd_exec = {data = plugins[p_name].commands[c_name], plugin = p_name, command = c_name} --split it into the function, and then the source end end end if cmd_exec then --is there really a command? local data = { -- Infrequently used data to pass onto the command being executed - usage = function(name) allium.tell(name, "&c"..cmd.." "..cmd_exec.command.usage) end, - autofill = cmd_exec.command.usage + error = function(text) + allium.tell(name, "&c"..(text or "!"..cmd.." "..cmd_exec.data.usage)) + end, + usage = cmd_exec.data.usage } local function exec_command() - local stat, err = pcall(cmd_exec.command.command, name, args, data) --Let's execute the command in a safe environment that won't kill allium + local stat, err = pcall(cmd_exec.data.command, name, args, data) --Let's execute the command in a safe environment that won't kill allium if stat == false then--it crashed... - allium.tell(name, "&4"..cmd.." crashed! This is likely not your fault, but the developer's. Please contact the developer of &a"..cmd_exec.plugin.."&4. Error:\n&c"..err) + allium.tell(name, "&4"..cmd_exec.command.." crashed! This is likely not your fault, but the developer's. Please contact the developer of &a"..cmd_exec.plugin.."&4. Error:\n&c&h(Click here to place error into chat prompt, so you may copy it if needed for an issue report)&s("..err:gsub("[(]", "["):gsub("[)]", "]")..")"..err.."&r") printError(cmd.." errored. Error:\n"..err) end end diff --git a/allium.nfp b/allium.nfp index 8a09be9..22ec6ce 100644 --- a/allium.nfp +++ b/allium.nfp @@ -8,8 +8,8 @@ aa66a2a 5 d d - d 5 5 d d + d \ No newline at end of file diff --git a/plugins/allium-stem.lua b/plugins/allium-stem.lua index 3b08b08..01bc643 100644 --- a/plugins/allium-stem.lua +++ b/plugins/allium-stem.lua @@ -20,7 +20,7 @@ local help = function(name, args, data) info[#info+1] = "&c&s(!"..args[1]..":"..cmd_name..")&h(!"..args[1]..":"..cmd_name..entry.usage..")!"..cmd_name.."&r: "..entry.info end else - allium.tell(name, "&cPlugin "..args[1].." does not exist") + data.error("Plugin "..args[1].." does not exist") return end next_command = next_command..args[1].." " @@ -54,7 +54,7 @@ local help = function(name, args, data) end if out_str == "" or page <= 0 then - allium.tell(name, "&cPage does not exist.") + data.error("Page does not exist.") return end @@ -67,30 +67,6 @@ local help = function(name, args, data) allium.tell(name, out_str, true) end ---[[local function repeatName(name, message) -- Put this in BagelBot! - local prefixes = allium.getPersistence("prefixes") - local nicks = allium.getPersistence("nicknames") - local rank = betaBot.getLevel(name)+1 - if not prefixes then - prefixes = { - user = {}, - ranks = { - "&r[&amember&r]", - "&r[&eVIP&r]", - "&r[&cadmin&r]", - } - } - allium.setPersistence("prefixes", prefixes) - end - if not nicks then - nicks = {} - allium.setPersistence("nicknames", nicks) - end - local nick = nicks[name] or name - local prefix = prefixes.user[name] or prefixes.ranks[rank] or "" - commands.tellraw("@a", color.format(prefix.." &r<"..nick.."&r> "..message)) -end]] - local credits = function(name) allium.tell(name, "This project was cultivated with love by &a&h(Check out his repo!)&i(https://github.com/hugeblank)hugeblank&r.\nCommand formatting API provided graciously by &1&h(Check out his repo!)&i(https://github.com/roger109z)roger109z&r.\nContribute and report issues to allium here: &9&n&h(Check out where allium is grown!)&ihttps://github.com/hugeblank/allium") end diff --git a/raisin b/raisin index 6a48d1b..7cf2f14 160000 --- a/raisin +++ b/raisin @@ -1 +1 @@ -Subproject commit 6a48d1b346bca282f1540753c8ee4109d17c06ba +Subproject commit 7cf2f147d262ab0c71547f877f385500517bc85f diff --git a/startup.lua b/startup.lua index 35b6c05..e1b454d 100644 --- a/startup.lua +++ b/startup.lua @@ -36,6 +36,6 @@ for _, side in pairs(peripheral.getNames()) do if exit then break end end -- Rebooting or exiting -print("Rebooting in 3 seconds") +print("Rebooting in 5 seconds") print("Press any key to cancel") -parallel.waitForAny(function() repeat until os.pullEvent("char") end, function() sleep(3) os.reboot() end) \ No newline at end of file +parallel.waitForAny(function() repeat until os.pullEvent("char") end, function() sleep(5) os.reboot() end) \ No newline at end of file From aaa9c41f86263c536d24e8595ff14993fee9cfcf Mon Sep 17 00:00:00 2001 From: hugeblank Date: Wed, 30 Jan 2019 00:20:03 -0800 Subject: [PATCH 5/9] Tweaks of Moderate Importance - Patched a bug in the startup file - Added debug option in startup to disable repo grabbing - color.lua's action text now searches for [[]] rather than () - All files affected by above have been changed to the standard - Added allium.forEachPlayer - a function that takes in a function, wraps it, provides a players name, and then executes those wrapped functions in parallel - Added allium.getPosition - a function that teleports an armor stand to the player, gets the coordinates, and then returns them - Added a thread that's constantly scanning players. This thread now emits 'player_join' and 'player' quit events - Changed how information per command is generated and extrapolated - The past 4 changes have yet to be documented, I am going to be moving documentation onto a wiki. - Updated allium-stem to handle new information parsing - Threads created under a plugin now return. Unlike the aforementioned 'past 4 changes', this was documented in the readme - !help in allium-stem now handles 'plugin:command' input, providing information that can now be added as a result of the information parsing changes - Raisin has been updated to the latest version --- README.md | 2 +- allium.lua | 109 ++++++++++++++++++++++++------ color.lua | 50 +++++++------- plugins/allium-stem.lua | 145 +++++++++++++++++++++++++++------------- raisin | 2 +- startup.lua | 42 +++++------- 6 files changed, 229 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index 82981fc..8b39cf0 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ _string_ `side`: The location of the chat recorder that allium is using - **Parameters** - _function_: function to turn into a thread - **Returns** - - _none_ + - _table_: table containing a wrapped instance of this thread (see Raisin's thread API [documentation](https://github.com/hugeblank/raisin/wiki)) `setPersistence`: Sets data that will remain persistent across a reboot of Allium. - **Parameters** diff --git a/allium.lua b/allium.lua index 6d288eb..2802257 100644 --- a/allium.lua +++ b/allium.lua @@ -12,7 +12,7 @@ term.setCursorPos(1, 1) print("Loading Allium") print("Initializing API") -local label = "<&r&dAll&5&h(Hugeblank was here. Hi.)&i(https://www.youtube.com/watch?v=PomZJao7Raw)i&r&dum&r>" --bot title +local label = "<&r&dAll&5&h[[Hugeblank was here. Hi.]]&i[[https://www.youtube.com/watch?v=PomZJao7Raw]]i&r&dum&r>" --bot title local raisin, color = require("raisin.raisin"), require("color") --Sponsored by roger109z local allium = {} -- API table local group = {thread = raisin.group.add(1) , command = raisin.group.add(2)} -- threads first, commands second, plugin groups third @@ -61,20 +61,54 @@ allium.getPlayers = function() return out end -allium.getInfo = function(plugin) -- Get the information of all plugins, or a single plugin - assert(plugin == nil or type(plugin) == "string", "Invalid argument #1 (string expected, got"..type(plugin)..")", 3) - if plugin then - plugin = allium.sanitize(plugin) +allium.forEachPlayer = function(func) + assert(type(func) == "function", "Invalid argument #1 (function expected, got "..type(func)..")") + local threads = {} + local players = allium.getPlayers() + local mentioned, error = false + for i = 1, #players do + threads[#threads+1] = function() + local suc, err = pcall(func, players[i]) + if not suc and not mentioned then + error = err + mentioned = true + end + end end - assert(command == nil or type(command) == "string", "Invalid argument #2 (string expected, got"..type(command)..")", 3) - if command then - assert(plugin, "Invalid argument #1 (string expected, got"..type(plugin)..")", 3) + parallel.waitForAll(unpack(threads)) + if not mentioned then + return true + else + return false, error end - if plugin then - assert(plugins[plugin], "Invalid argument #1 (plugin "..plugin.." does not exist)", 3) - if command then - assert(plugins[plugin].commands[command], "Invalid argument #2 (command "..command.." does not exist in plugin "..plugin..")", 3) +end + +allium.getPosition = function(name) + assert(type(name) == "nil" or type(name) == "string", "Invalid argument #1 (expected string or nil, got "..type(name)..")") + local position = {} -- Player position values + local suc, tbl + parallel.waitForAll(function() -- Execute tp to player, and value check simultaneously for minimum latency + suc = commands.exec("tp @e[type=minecraft:armor_stand,team=allium_trackers] "..name) + end, function() + _, tbl = commands.exec("tp @e[type=minecraft:armor_stand,team=allium_trackers] ~ ~ ~") + end) + commands.exec("tp @e[type=minecraft:armor_stand,team=allium_trackers] "..table.concat({commands.getBlockPosition()}, " ")) + if suc then + local pos_str = tbl[1]:gsub("Teleported Armor Stand to ", ""):gsub("[,]", "") + for value in pos_str:gmatch("%S+") do + position[#position+1] = value end + else + return false + end + return unpack(position) +end + +allium.getInfo = function(plugin) -- Get the information of all plugins, or a single plugin + assert(plugin == nil or type(plugin) == "string", "Invalid argument #1 (nil or string expected, got"..type(plugin)..")") + if plugin then + plugin = allium.sanitize(plugin) + assert(plugins[plugin], "Invalid argument #1 (plugin "..plugin.." does not exist)") end if plugin then local res = {[plugin] = {}} @@ -109,18 +143,20 @@ allium.register = function(p_name, fullname) local funcs = {} local this = plugins[real_name] - funcs.command = function(c_name, command, info, usage) -- name: name | command: executing function | info: help information | usage: string for improper inputs + funcs.command = function(c_name, command, info, usage) -- name: name | command: executing function | info: help information | usage: table of strings for improper inputs assert(type(c_name) == "string", "Invalid argument #1 (string expected, got "..type(c_name)..")") local real_name = allium.sanitize(c_name) assert(type(command) == "function", "Invalid argument #2 (function expected, got "..type(command)..")") assert(this.commands[real_name] == nil, "Invalid argument #2 (command exists under name "..real_name.." for plugin "..this.name..")") - assert(type(info) == "string", "Invalid argument #3 (string expected, got "..type(info)..")") + assert(type(info) == "string" or type(info) == "table" or not info, "Invalid argument #3 (string, table, or nil expected, got "..type(info)..")") + if type(info) == "string" then info = {generic = info} end + assert(info.generic, "Invalid argument #3 ('generic' info expected, none found)") this.commands[real_name] = {command = command, info = info, usage = usage} end funcs.thread = function(thread) assert(type(thread) == "function", "Invalid argument #1 (function expected, got "..type(thread)..")") - raisin.thread.add(thread, 0, group.thread) + return raisin.thread.wrap(raisin.thread.add(thread, 0, group.thread), group.thread) end funcs.getPersistence = function(name) @@ -200,7 +236,7 @@ do -- Plugin loading process end end -local main = function() +local interpreter = function() -- Main command interpretation thread while true do local _, message, _, name = os.pullEvent("chat_capture") --Pull chat messages if string.find(message, "!") == 1 then --are they for allium? @@ -240,27 +276,58 @@ local main = function() local function exec_command() local stat, err = pcall(cmd_exec.data.command, name, args, data) --Let's execute the command in a safe environment that won't kill allium if stat == false then--it crashed... - allium.tell(name, "&4"..cmd_exec.command.." crashed! This is likely not your fault, but the developer's. Please contact the developer of &a"..cmd_exec.plugin.."&4. Error:\n&c&h(Click here to place error into chat prompt, so you may copy it if needed for an issue report)&s("..err:gsub("[(]", "["):gsub("[)]", "]")..")"..err.."&r") + allium.tell(name, "&4"..cmd_exec.command.." crashed! This is likely not your fault, but the developer's. Please contact the developer of &a"..cmd_exec.plugin.."&4. Error:\n&c&h[[Click here to place error into chat prompt, so you may copy it if needed for an issue report]]&s[["..err.."]]"..err.."&r") printError(cmd.." errored. Error:\n"..err) end end raisin.thread.add(exec_command, 0, group.command) else --this isn't even a valid command... - allium.tell(name, "&6Invalid Command, use &c&g(!allium:help)!help&r&6 for assistance.") --bleh! + allium.tell(name, "&6Invalid Command, use &c&g[[!allium:help]]!help&r&6 for assistance.") --bleh! end end end end -raisin.thread.add(main, 0) +local scanner = function() -- Login/out scanner thread + local online = {} + while true do + local cur_players = allium.getPlayers() + local organized = {} + for i = 1, #cur_players do -- Sort players in a way that's useful + organized[cur_players[i]] = cur_players[i] + end + for _, name in pairs(organized) do + if online[name] == nil then + online[name] = name + os.queueEvent("player_join", name) + end + end + for _, name in pairs(online) do + if organized[name] == nil then + online[name] = nil + os.queueEvent("player_quit", name) + end + end + sleep() + end +end + +raisin.thread.add(interpreter, 0) +raisin.thread.add(scanner, 1) -if not fs.exists("persistence.ltn") then --In the situation that this is a first installation, let's add persistence.ltn +if not fs.exists("persistence.ltn") then --In the situation that this is a first installation, let's do some setup local fpers = fs.open("persistence.ltn", "w") fpers.write("{}") fpers.close() end +if not commands.exec("testfor @e[r=1,type=minecraft:armor_stand,team=allium_trackers]") then + commands.execAsync("kill @e[type=minecraft:armor_stand,team=allium_trackers]") + commands.execAsync("scoreboard teams add allium_trackers") + commands.execAsync("summon minecraft:armor_stand ~ ~ ~ {Marker:1,NoGravity:1,Invisible:1}") + commands.execAsync("scoreboard teams join allium_trackers @e[r=1,type=minecraft:armor_stand]") +end + print("Allium started.") allium.tell("@a", "&eHello World!") -sleep() raisin.manager.run() diff --git a/color.lua b/color.lua index 1d92782..45c45b8 100644 --- a/color.lua +++ b/color.lua @@ -51,8 +51,8 @@ local dCurrent = { local function escape(tbl) for k, v in pairs(tbl) do if v[2]:find("\\") == v[2]:len() then - tbl[k] = {v[1], v[2]:sub(1, -1).."&"..tbl[tonumber(k)+1][1]..tbl[tonumber(k)+1][2]} - table.remove(tbl, tonumer(k)+1) + tbl[k] = {v[1], v[2]:sub(1, -2).."&"..tbl[tonumber(k)+1][1]..tbl[tonumber(k)+1][2]} + table.remove(tbl, tonumber(k)+1) local ret = escape(tbl) return ret end @@ -78,46 +78,46 @@ this.format = function(sText, bAction) local seperated = {} sText = "&r"..sText for k in string.gmatch(sText, "[^&]+") do - seperated[#seperated+1] = {string.sub(k, 1, 1), string.sub(k, 2)} + seperated[#seperated+1] = {k:sub(1, 1), k:sub(2)} end local outText = '["",' local prev seperated = escape(seperated) - for k, v in pairs(seperated) do - if cTable[v[1]] ~= nil then - current["color"] = cTable[v[1]] - elseif formats[v[1]] ~= nil then - if current["format"][formats[v[1]]] == false then - current["format"][formats[v[1]]] = true + for _, toParse in pairs(seperated) do + if cTable[toParse[1]] ~= nil then + current["color"] = cTable[toParse[1]] + elseif formats[toParse[1]] ~= nil then + if current["format"][formats[toParse[1]]] == false then + current["format"][formats[toParse[1]]] = true else - current["format"][formats[v[1]]] = false + current["format"][formats[toParse[1]]] = false end - elseif actions[v[1]] ~= nil then - current["action"] = actions[v[1]] - local ind = string.find(v[2], ")") + elseif actions[toParse[1]] ~= nil then + current["action"] = actions[toParse[1]] + local ind, bck = string.find(toParse[2], "%[%[.*%]%]") if ind ~= nil then - current["actionText"] = string.sub(v[2], 2, ind-1) - v[2] = v[2]:sub(ind+1) + current["actionText"] = toParse[2]:sub(ind+2, bck-2) + toParse[2] = toParse[2]:sub(bck+1) else - current["actionText"] = v[2] + current["actionText"] = toParse[2] end - elseif other[v[1]] ~= nil then - if other[v[1]] == "hoverEvent" then + elseif other[toParse[1]] ~= nil then + if other[toParse[1]] == "hoverEvent" then current["hoverEvent"] = true - local ind = string.find(v[2], ")") + local ind, bck = string.find(toParse[2], "%[%[.*%]%]") if ind ~= nil then - current["hoverText"] = this.format(string.sub(v[2], 2, ind-1), false) - v[2] = v[2]:sub(ind+1) + current["hoverText"] = this.format(toParse[2]:sub(ind+2, bck-2), false) + toParse[2] = toParse[2]:sub(bck+1) else - current["hoverText"] = v[2] + current["hoverText"] = toParse[2] end - elseif other[v[1]] == "reset" then + elseif other[toParse[1]] == "reset" then current = copy(dCurrent) end else - v[2] = "&"..v[1]..v[2] + toParse[2] = "&"..toParse[1]..toParse[2] end - outText = outText..'{"text":"'..v[2]..'","color":"'..current["color"]..'"' + outText = outText..'{"text":"'..toParse[2]..'","color":"'..current["color"]..'"' for k, v in pairs(current["format"]) do if v then outText = outText..",\""..k.."\":true" diff --git a/plugins/allium-stem.lua b/plugins/allium-stem.lua index 01bc643..a5ae565 100644 --- a/plugins/allium-stem.lua +++ b/plugins/allium-stem.lua @@ -6,34 +6,25 @@ local help = function(name, args, data) local out_str = "" local next_command = "!allium:help " - if args[1] == nil then - page = 1 - elseif not tonumber(args[1]) then - args[1] = allium.sanitize(args[1]) - if allium.getName(args[1]) then - for cmd_name, entry in pairs((allium.getInfo(args[1]))[args[1]]) do - if entry.usage then - entry.usage = " "..entry.usage - else - entry.usage = "" - end - info[#info+1] = "&c&s(!"..args[1]..":"..cmd_name..")&h(!"..args[1]..":"..cmd_name..entry.usage..")!"..cmd_name.."&r: "..entry.info + local function run() + for i = (cmds_per*(page-1))+1, (cmds_per*page) do + if info[i] then + out_str = out_str..info[i].."\n" end - else - data.error("Plugin "..args[1].." does not exist") - return end - next_command = next_command..args[1].." " - if tonumber(args[2]) then - page = tonumber(args[2]) + if out_str == "" or page <= 0 then + data.error("Page does not exist.") + return end - elseif tonumber(args[1]) then - page = tonumber(args[1]) - else - meta.usage(name) + out_str = "&2===================&r &dAll&5i&r&dum&e Help Menu&r &2===================&r\n"..out_str + local template = #(" << "..page.."/"..math.ceil(#info/cmds_per).." >> ") + local sides = math.ceil((64/2)-template) + out_str = out_str.."&2"..string.rep("=", sides).."&r &6&l&h[[Previous Page]]&g[["..next_command..(page-1).."]]<<&r&c&l "..page.."/"..math.ceil(#info/cmds_per).." &r&6&l&h[[Next Page]]&g[["..next_command..(page+1).."]]>>&r &2"..string.rep("=", sides).."&r" + allium.tell(name, out_str, true) + return end - if #info == 0 then + if tonumber(args[1]) or not args[1] then -- The first argument is nothing or a page number local data = allium.getInfo() for p_name, commands in pairs(data) do for cmd_name, entry in pairs(commands) do @@ -42,46 +33,104 @@ local help = function(name, args, data) else entry.usage = "" end - info[#info+1] = "&c&s(!"..p_name..":"..cmd_name..")&h(!"..p_name..":"..cmd_name..entry.usage..")!"..p_name..":"..cmd_name.."&r: "..entry.info + info[#info+1] = "&c&s[[!"..p_name..":"..cmd_name.."]]&h[[!"..p_name..":"..cmd_name..entry.usage.."]]!"..p_name..":"..cmd_name.."&r: "..entry.info.generic end end - end - - for i = (cmds_per*(page-1))+1, (cmds_per*page) do - if info[i] then - out_str = out_str..info[i].."\n" + if tonumber(args[1]) then + page = tonumber(args[1]) + end + return run() + else -- The first argument is a plugin/command + args[1] = allium.sanitize(args[1]) + if tonumber(args[2]) then + page = tonumber(args[2]) + end + next_command = next_command..args[1].." " + local cnp = args[1]:find(":") + if cnp then -- This is a command and plugin + local p_name, c_name = args[1]:sub(1, cnp-1), args[1]:sub(cnp+1, -1) + if allium.getName(p_name) then + local c_info = allium.getInfo(p_name)[p_name][c_name] + if c_info then + next_command = next_command..args[1].." " + local function addDetails(i_table, label, pre_str, sug_cmd, include) + if not include then + if i_table.noclick then + info[#info+1] = pre_str.."<&a"..label.."&r>: "..i_table.generic + elseif i_table.optional then + info[#info+1] = pre_str.."[&a"..label.."&r]: "..i_table.generic + elseif not (i_table.noclick or i_table.optional) then + info[#info+1] = pre_str.."<&a&h[[Add this parameter]]&s[["..sug_cmd.." ]]"..label.."&r>: "..i_table.generic + end + end + for param, param_info in pairs(i_table) do + if param ~= "generic" and param ~= "optional" and param ~= "noclick" then + addDetails(param_info, param, " "..pre_str, sug_cmd.." "..param) + end + end + end + info[#info+1] = "&c&s[[!"..p_name..":"..c_name.."]]&h[[!"..c_name..c_info.usage.."]]!"..c_name.."&r: "..c_info.info.generic + addDetails(c_info.info, c_name, "&6-&r ", "!"..p_name..":"..c_name, true) + return run() + else + data.error("Command !"..args[1].." does not exist") + return + end + else + data.error("Plugin "..args[1].." does not exist") + return + end + else -- This is just a plugin + if allium.getName(args[1]) then + for cmd_name, entry in pairs((allium.getInfo(args[1]))[args[1]]) do + if entry.usage then + entry.usage = " "..entry.usage + else + entry.usage = "" + end + info[#info+1] = "&c&s[[!"..args[1]..":"..cmd_name.."]]&g[[!help "..args[1]..":"..cmd_name.."]]&h[[!"..args[1]..":"..cmd_name..entry.usage.."]]!"..cmd_name.."&r: "..entry.info.generic + end + return run() + else + data.error("Plugin "..args[1].." does not exist") + return + end end end - - if out_str == "" or page <= 0 then - data.error("Page does not exist.") - return - end - - out_str = "&2===================&r &dAll&5i&r&dum&e Help Menu&r &2===================&r\n"..out_str - - local template = #(" << "..page.."/"..math.ceil(#info/cmds_per).." >> ") - local sides = math.ceil((64/2)-template) - - out_str = out_str.."&2"..string.rep("=", sides).."&r &6&l&h(Previous Page)&g("..next_command..(page-1)..")<<&r&c&l "..page.."/"..math.ceil(#info/cmds_per).." &r&6&l&h(Next Page)&g("..next_command..(page+1)..")>>&r &2"..string.rep("=", sides).."&r" - allium.tell(name, out_str, true) end local credits = function(name) - allium.tell(name, "This project was cultivated with love by &a&h(Check out his repo!)&i(https://github.com/hugeblank)hugeblank&r.\nCommand formatting API provided graciously by &1&h(Check out his repo!)&i(https://github.com/roger109z)roger109z&r.\nContribute and report issues to allium here: &9&n&h(Check out where allium is grown!)&ihttps://github.com/hugeblank/allium") + allium.tell(name, "This project was cultivated with love by &a&h[[Check out his repo!]]&i[[https://github.com/hugeblank]]hugeblank&r.\nCommand formatting API provided graciously by &1&h[[Check out his repo!]]&i[[https://github.com/roger109z]]roger109z&r.\nContribute and report issues to allium here: &9&n&h[[Check out where allium is grown!]]&ihttps://github.com/hugeblank/allium") end local plugins = function(name) local pluginlist = {} local str = "" local plugins = allium.getInfo() - for p_name in pairs(plugins) do - pluginlist[#pluginlist+1] = "&h(Tag: "..p_name..")"..allium.getName(p_name) + for p_name in pairs(plugins) do + local p_str = "&h[[Tag: "..p_name.."]]" + if plugins[p_name]["credits"] then + p_str = p_str.."&g[[!"..p_name..":credits]]" + end + print(p_str) + pluginlist[#pluginlist+1] = p_str..allium.getName(p_name) end str = table.concat(pluginlist, "&r, &a") allium.tell(name, "Plugins installed: &a"..str) end -stem.command("help", help, "This command! Helpful.", "[page/plugin name], [page]") -stem.command("plugins", plugins, "Lists the name of all plugins installed on allium") -stem.command("credits", credits, "Provides credits where they are due") \ No newline at end of file +local info = { + help = { + generic = "This command! Helpful." + }, + plugins = { + generic = "Lists the name of all plugins installed on allium" + }, + credits = { + generic = "Provides credits where they are due" + } +} + +stem.command("help", help, info.help, "[page/plugin name], [page]") +stem.command("plugins", plugins, info.plugins) +stem.command("credits", credits, info.credits) \ No newline at end of file diff --git a/raisin b/raisin index 7cf2f14..f165499 160000 --- a/raisin +++ b/raisin @@ -1 +1 @@ -Subproject commit 7cf2f147d262ab0c71547f877f385500517bc85f +Subproject commit f165499348374927fdbe65052d9e978dd609cc79 diff --git a/startup.lua b/startup.lua index e1b454d..e81b52b 100644 --- a/startup.lua +++ b/startup.lua @@ -1,18 +1,21 @@ shell.openTab("shell") +local debug = false -- for use when debugging, auto-update script doesn't get triggered -- Checking for a repolist shell executable -if fs.exists("repolist.csh") then - -- Update all plugins and programs on the repolist - local file = fs.open("repolist.csh", "r") - for k in file.readLine do - shell.run(k) +if not debug then + if fs.exists("repolist.csh") then + -- Update all plugins and programs on the repolist + local file = fs.open("repolist.csh", "r") + for k in file.readLine() do + shell.run(k) + end + file.close() + else + -- Generate a repolist file + local file = fs.open("repolist.csh", "w") + file.write("gitget hugeblank Allium master /") --Forkers change this to their repository. + file.close() + printError("No valid repo file, default file created") end - file.close() -else - -- Generate a repolist file - local file = fs.open("repolist.csh", "w") - file.write("gitget hugeblank/Allium") --Forkers change this to their repository. - file.close() - printError("No valid repo file, default file created") end -- Clearing the screen term.setBackgroundColor(colors.black) @@ -22,19 +25,8 @@ term.setCursorPos(1, 1) -- Running Allium shell.run("allium.lua") -- Removing all captures -local exit = false -for _, side in pairs(peripheral.getNames()) do - if peripheral.getMethods(side) then - for _, method in pairs(peripheral.getMethods(side)) do - if method == "uncapture" then - peripheral.call(side, method, ".") - exit = true - break - end - end - end - if exit then break end -end +peripheral.call(allium.side, "uncapture", ".") + -- Rebooting or exiting print("Rebooting in 5 seconds") print("Press any key to cancel") From 6f8caefb73da5fcf0f88c7f2f6e96c8cf99fc5ed Mon Sep 17 00:00:00 2001 From: hugeblank Date: Thu, 31 Jan 2019 00:39:13 -0800 Subject: [PATCH 6/9] Commenting | Licensing | Nullifying - Improved comment legibility slightly - Set global table "allium" to nil on termination - Updated startup to account for this change - Allium now has a License! MIT FTW. --- LICENSE | 21 +++++++++++++++++++++ allium.lua | 27 ++++++++++++++++----------- plugins/allium-stem.lua | 7 ++++--- startup.lua | 11 ++++++++++- 4 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c6b8ed6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Todd Lange + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/allium.lua b/allium.lua index 2802257..084bee7 100644 --- a/allium.lua +++ b/allium.lua @@ -238,38 +238,42 @@ end local interpreter = function() -- Main command interpretation thread while true do - local _, message, _, name = os.pullEvent("chat_capture") --Pull chat messages - if string.find(message, "!") == 1 then --are they for allium? + local _, message, _, name = os.pullEvent("chat_capture") -- Pull chat messages + if string.find(message, "!") == 1 then -- Are they for allium? args = {} - for k in string.gmatch(message, "%S+") do --put all arguments spaced out into a table + for k in string.gmatch(message, "%S+") do -- Put all arguments spaced out into a table args[#args+1] = k end local cmd = args[1]:sub(2, -1) -- Strip the ! - table.remove(args, 1) --remove the first parameter given (!command) + table.remove(args, 1) -- Remove the first parameter given (!command) local cmd_exec - if not string.find(cmd, ":") then --did they not specify the plugin source? - for p_name, plugin in pairs(plugins) do --nope... gonna have to find it for them. + if not string.find(cmd, ":") then -- Did they not specify the plugin source? + for p_name, plugin in pairs(plugins) do -- Nope... gonna have to find it for them. for c_name, data in pairs(plugin.commands) do if c_name == cmd then --well I found it, but there may be more... - cmd_exec = {data = data, plugin = p_name, command = c_name} --split into command function, source + cmd_exec = {data = data, plugin = p_name, command = c_name} -- Split into command function, plugin name, and command name break end end if cmd_exec then break end -- Exit this loop, we've found the command we're looking for end - else --hey they did! +1 karma. + else -- Hey they did! +1 karma. local splitat = string.find(cmd, ":") local p_name, c_name = string.sub(cmd, 1, splitat-1), string.sub(cmd, splitat+1, -1) if plugins[p_name] then --check plugin existence if plugins[p_name].commands[c_name] then --check command existence - cmd_exec = {data = plugins[p_name].commands[c_name], plugin = p_name, command = c_name} --split it into the function, and then the source + cmd_exec = {data = plugins[p_name].commands[c_name], plugin = p_name, command = c_name} -- Split it into the function, and then the source end end end - if cmd_exec then --is there really a command? + if cmd_exec then -- Is there really a command? local data = { -- Infrequently used data to pass onto the command being executed error = function(text) - allium.tell(name, "&c"..(text or "!"..cmd.." "..cmd_exec.data.usage)) + local str = "Invalid or missing parameter(s)" + if cmd_exec.data.usage then + str = "!"..cmd.." "..cmd_exec.data.usage + end + allium.tell(name, "&c"..(text or str)) end, usage = cmd_exec.data.usage } @@ -331,3 +335,4 @@ end print("Allium started.") allium.tell("@a", "&eHello World!") raisin.manager.run() +_G.allium = nil \ No newline at end of file diff --git a/plugins/allium-stem.lua b/plugins/allium-stem.lua index a5ae565..57fe244 100644 --- a/plugins/allium-stem.lua +++ b/plugins/allium-stem.lua @@ -55,9 +55,9 @@ local help = function(name, args, data) next_command = next_command..args[1].." " local function addDetails(i_table, label, pre_str, sug_cmd, include) if not include then - if i_table.noclick then + if i_table.noclick then -- If the parameter is not intended to be clicked (Eg: a username) info[#info+1] = pre_str.."<&a"..label.."&r>: "..i_table.generic - elseif i_table.optional then + elseif i_table.optional then -- If the parameter is not required info[#info+1] = pre_str.."[&a"..label.."&r]: "..i_table.generic elseif not (i_table.noclick or i_table.optional) then info[#info+1] = pre_str.."<&a&h[[Add this parameter]]&s[["..sug_cmd.." ]]"..label.."&r>: "..i_table.generic @@ -69,6 +69,7 @@ local help = function(name, args, data) end end end + if not c_info.usage then c_info.usage = "" end info[#info+1] = "&c&s[[!"..p_name..":"..c_name.."]]&h[[!"..c_name..c_info.usage.."]]!"..c_name.."&r: "..c_info.info.generic addDetails(c_info.info, c_name, "&6-&r ", "!"..p_name..":"..c_name, true) return run() @@ -131,6 +132,6 @@ local info = { } } -stem.command("help", help, info.help, "[page/plugin name], [page]") +stem.command("help", help, info.help, "[page | plugin name], [page]") stem.command("plugins", plugins, info.plugins) stem.command("credits", credits, info.credits) \ No newline at end of file diff --git a/startup.lua b/startup.lua index e81b52b..19c2508 100644 --- a/startup.lua +++ b/startup.lua @@ -25,7 +25,16 @@ term.setCursorPos(1, 1) -- Running Allium shell.run("allium.lua") -- Removing all captures -peripheral.call(allium.side, "uncapture", ".") +for _, side in pairs(peripheral.getNames()) do -- Finding the chat module + if peripheral.getMethods(side) then + for _, method in pairs(peripheral.getMethods(side)) do + if method == "uncapture" then + peripheral.call(allium.side, "uncapture", ".") + break + end + end + end +end -- Rebooting or exiting print("Rebooting in 5 seconds") From 693d63562de2ff5a72a00bb3071b7a835557f3c0 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Thu, 31 Jan 2019 02:24:03 -0800 Subject: [PATCH 7/9] Update README to reference wiki --- README.md | 143 +----------------------------------------------------- 1 file changed, 2 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index 8b39cf0..7eeca41 100644 --- a/README.md +++ b/README.md @@ -27,149 +27,10 @@ The installer installs: - persistence.ltn - A _Lua Table Notation_ file containing all serialized persistence entries for each plugin. -## Stem Commands -These are the commands that make up the backbone of Allium, the stem per se. +**Want More?** Check out the [wiki](https://github.com/hugeblank/Allium/wiki/)! -`!help`: Lists the info entries for the installed plugins - -`!plugins`: Lists the plugins that are installed, based on the name of the directory that they're found in. - -`!credits`: Links to the github repo for [Allium](https://github.com/hugeblank/Allium), and to the people that made Allium. - -## API -Quick reference for plugin developers: - -### `allium` -#### Methods: -`assert`: Lua's generic assert, with the ability to set the error level -- **Parameters** - - _boolean_: condition to test - - _string_: error message - - _number_: error level -- **Returns** - - _none_ - -`sanitize`: Sanitize plugin names to meet allium's ID standards -- **Parameters** - - _string_: plugin/command name string -- **Returns** - - _string_: valid allium plugin/command ID - -`tell`: Output colorcode formatted text to the user, using the & and then a hexadecimal symbol. Additional codes are also provided that perform other actions. -- **Parameters** - - _string_: name of user - - _string_: text __OR__ _table_: list of text - - _[string]_: label replacement __OR__ _[boolean]_: hide label -- **Returns** - - _string_: execution results - -`getPlayers`: Lists all online players -- **Parameters** - - _none_ -- **Returns** - - _table_: list of online players - -`getInfo`: Get information for one or all plugins -- **Parameters** - - _[string]_: allium plugin ID -- **Returns** - - _table_: table of information organized as `table[plugin][command] = information` - -`getName`: Get the human readable name from the plugin ID -- **Parameters** - - _string_: allium plugin ID -- **Returns** - - _string_: human readable plugin name - -`register`: The big boy, Register an Allium plugin -- **Parameters** - - _string_: plugin name, converted to allium plugin ID - - _[string]_: optional manually set human readable plugin name -- **Returns** - - _table_: list of functions to register commands/threads/persistent data (see below) -#### Other: -_string_ `side`: The location of the chat recorder that allium is using - -### `allium.register` -#### Methods: -`command`: Register a command within this plugin -- **Parameters** - - _string_: command name - - _function_: function to execute - - _string_: information about the command - - _[string]_: command usage formatted as ` [optional | second | arguments]` -- **Returns** - - _none_ - -`thread`: Register a thread within this plugin -- **Parameters** - - _function_: function to turn into a thread -- **Returns** - - _table_: table containing a wrapped instance of this thread (see Raisin's thread API [documentation](https://github.com/hugeblank/raisin/wiki)) - -`setPersistence`: Sets data that will remain persistent across a reboot of Allium. -- **Parameters** - - _string_: name of the persistent value - - _any_: data to assign to value -- **Returns** - - _none_ - -`getPersistence`: Sets data that will remain persistent across a reboot of Allium. -- **Parameters** - - _string_: name of the persistent value -- **Returns** - - _any_: data that was assigned to that value ---- -## Command Data - Information on what is given to a command on invocation: - - _string_: name of the user that invoked the command - - _table_: arguments provided after the invocation (Eg: `!help allium 2` args: `{"allium", "2"}`) - - _table_: list of infrequently used, but useful utilities - - `error` _function_ | Quick and easy way to return command usage, or other information to the executor - - **Parameters** - - _[string]_: error message, if left nil uses the command usage string - - **Returns** - - _none_ - - `usage` _string_ | Provides raw access to the usage string for the command ---- -## Formatting Codes -The following characters are all valid for formatting in `allium.tell` when prefixxed with an `&`: - -### Colors -- r - reset formatting -- 0 - black -- 1 - dark blue -- 2 - dark green -- 3 - dark aqua -- 4 - dark red -- 5 - dark purple -- 6 - gold -- 7 - gray -- 8 - dark gray -- 9 - blue -- a - green -- b - aqua -- c - red -- d - light purple -- e - yellow -- f - white - -### Actions -- g - execute text | `&g(!allium:help)Click for help!&r` -- h - hover text | `&h(Hi there :P)Mouse over me!&r` -- i - clickable link | `&i(https://google.com)Go to google!&r` -- s - suggest text | `&s(I'm in your bar now!)Click on me!&r` - -### Emphases -- k - obfuscated -- l - bold -- m - strikethrough -- n - italic -- o - underline - ---- ## Forking this repository It's worth noting that there are some places you might want to check out after you fork, and before you start testing your code. 1. The pastebin [installer](https://www.pastebin.com/LGwrkjxm). You are free to make your own installer to your fork with this code, simply change the `repo` string to "[your github username] [the name of your Allium repository] [the branch you want to clone from] [location]". -2. The startup file of your fork. There is a line that has a comment along with it. Change that repo name from the official Allium repository to your forked repository, similar to the style shown above. \ No newline at end of file +2. The startup file of your fork. Change the debug variable, and make sure to replace the marked line with your repo, like above. \ No newline at end of file From c44857e297d2c9efed0a0b31a118cfbe5b517cf1 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Thu, 31 Jan 2019 14:01:47 -0800 Subject: [PATCH 8/9] Recursive calls to subdirectories of plugins - Subdirectories of the main plugin directory will now be scanned for lua files. --- allium.lua | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/allium.lua b/allium.lua index 084bee7..8041bcf 100644 --- a/allium.lua +++ b/allium.lua @@ -218,11 +218,10 @@ _G.allium = allium -- Globalizing Allium API do -- Plugin loading process print("Loading plugins...") - local dir = shell.dir() - if fs.exists(dir.."plugins") then - for _, plugin in pairs(fs.list(dir.."plugins")) do - if not fs.isDir(dir.."plugins/"..plugin) then - local file, err = loadfile(dir.."plugins/"..plugin) + local function scopeDown(dir) + for _, plugin in pairs(fs.list(dir)) do + if (not fs.isDir(dir.."/"..plugin)) and plugin:find(".lua") then + local file, err = loadfile(dir.."/"..plugin) if not file then printError(err) else @@ -231,9 +230,17 @@ do -- Plugin loading process printError(err) end end + elseif fs.isDir(dir.."/"..plugin) then + scopeDown(dir.."/"..plugin) end end end + local dir = shell.dir() + if fs.exists(dir.."/plugins") then + scopeDown(dir.."/plugins") + else + fs.makeDir(dir.."/plugins") + end end local interpreter = function() -- Main command interpretation thread From abc780c318cec6b88060ff32897961968020b6af Mon Sep 17 00:00:00 2001 From: hugeblank Date: Thu, 31 Jan 2019 14:32:07 -0800 Subject: [PATCH 9/9] Insignificant Tweaks - Updated raisin documentation mention in README - Debugged the startup file to not crash when parsing the repolist --- README.md | 2 +- startup.lua | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7eeca41..3310231 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ It uses Computercraft's Command Computer, and Plethora Peripherals' Creative Cha The command computer can already do many things, being a programmable command block. Allium takes that power to the next level and expands functionality to allow for plugins to be registered. From there you can add commands that get triggered by players, threads that can do command based things without the need of a command to execute them, and data that can be stored in a persistent file so that things you want to hang onto don't get lost in the event of a crash or restart. -Allium uses **[Raisin](https://github.com/hugeblank/raisin/)**, a next generation thread manager made by me, hugeblank. If you're a prospective Allium plugin developer, you may want to skim the documentation, found in the Readme. +Allium uses **[Raisin](https://github.com/hugeblank/raisin/)**, a next generation thread manager made by me, hugeblank. If you're a prospective Allium plugin developer, you may want to skim the documentation, found on Raisin's [wiki](https://github.com/hugeblank/raisin/wiki/). Allium also uses a chat text formatting API provided by [roger109z](https://github.com/roger109z/). I (hugeblank) personally haven't touched it (even though it is in my repo) since he's created it as it works flawlessly. diff --git a/startup.lua b/startup.lua index 19c2508..2cbc3e8 100644 --- a/startup.lua +++ b/startup.lua @@ -4,9 +4,8 @@ local debug = false -- for use when debugging, auto-update script doesn't get tr if not debug then if fs.exists("repolist.csh") then -- Update all plugins and programs on the repolist - local file = fs.open("repolist.csh", "r") - for k in file.readLine() do - shell.run(k) + for line in io.lines("repolist.csh") do + shell.run(line) end file.close() else