From 343aff3d3cefd5c78f929048c9caa87ee9b035b5 Mon Sep 17 00:00:00 2001 From: min Date: Thu, 26 Feb 2026 08:22:57 -0500 Subject: [PATCH] feat: link implementation --- cfg.lua | 2 + chat.lua | 47 +++++++++++++-- cmds.lua | 15 ++++- index.lua | 157 +++++++++++++++++++++++++++++++++++++++++---------- tracking.lua | 3 +- 5 files changed, 186 insertions(+), 38 deletions(-) diff --git a/cfg.lua b/cfg.lua index cc52b60..7159ee2 100644 --- a/cfg.lua +++ b/cfg.lua @@ -1,5 +1,7 @@ return { prefix = "!", + linkToWS = nil, + sendToLink = false, users = { ["MinishCaps"] = { diff --git a/chat.lua b/chat.lua index 7b9afc1..6567340 100644 --- a/chat.lua +++ b/chat.lua @@ -2,15 +2,19 @@ local cfg = require("cfg") local boxes = { peripheral.find("chat_box") } +if #boxes == 0 then + error("no chat boxes :(") +end + local function ssleep(seconds) local fireAt = os.time() + (seconds / 50) local enqueued = {} - os.setAlarm(fireAt) + local myId = os.setAlarm(fireAt) while true do local ev = { os.pullEventRaw() } - if ev[1] == "alarm" then + if ev[1] == "alarm" and ev[2] == myId then break else table.insert(enqueued, ev) @@ -44,6 +48,38 @@ local function dispatch(callback) end end +local deb = { + username = nil, + message = nil, + uuid = nil, + hidden = nil, + at = 0, + fired = 0, +} +local function checkDebounce(username, message, uuid, hidden) + if + username ~= deb.username + or message ~= deb.message + or uuid ~= deb.uuid + or hidden ~= deb.hidden + or os.clock() - deb.at > 0.1 + or deb.fired > #boxes + then + deb.username = username + deb.message = message + deb.uuid = uuid + deb.hidden = hidden + deb.at = os.clock() + deb.fired = 0 + + return true + else + deb.fired = deb.fired + 1 + + return false + end +end + local function send(unm, msg, chan) local prefix = "&bSky" @@ -94,9 +130,9 @@ local function sayas(plr, msg) end) end -local function sayserver(msg) +local function saysquare(as, msg) dispatch(function(bx) - bx.sendMessage(msg, "Server", "[]") + bx.sendMessage(msg, as, "[]") end) end @@ -154,11 +190,12 @@ local function faketpa(tgtplr, sender, fakeplr, fakemsg, url) end return { + checkDebounce = checkDebounce, send = send, userBc = userBc, reportLog = reportLog, say = say, sayas = sayas, - sayserver = sayserver, + saysquare = saysquare, faketpa = faketpa, } diff --git a/cmds.lua b/cmds.lua index 8812dc1..3faf0e8 100644 --- a/cmds.lua +++ b/cmds.lua @@ -199,7 +199,7 @@ cmds.sayserver = { }, allowLimitedUser = true, proc = function(unm, what) - ch.sayserver(what) + ch.saysquare("Server", what) end, } @@ -220,6 +220,19 @@ cmds.faketpa = { end, } +cmds.link = { + alias = { "chatlink", "skylink", "bridge" }, + desc = "manage chat link", + args = { + { match = "boolean", desc = "on/off" }, + }, + allowAnybody = true, + proc = function(unm, state) + cfg.sendToLink = state + ch.send(unm, "updated link mode to " .. (state and "ON" or "OFF") .. "..", "link") + end +} + cmds.usage = { alias = { "u", "cmd", "c", "describe", "what", "command" }, desc = "how to use a command?", diff --git a/index.lua b/index.lua index 6e47b9f..9d64813 100644 --- a/index.lua +++ b/index.lua @@ -1,4 +1,4 @@ --- Skynet v1.2 // server +-- Skynet v1.3 // server -- orig. written by minish - 2023-10 -- revived 2025-01 @@ -13,6 +13,38 @@ local cmds = require("cmds") settings.set("shell.allow_disk_startup", false) --#endregion +--#region Listener States +local wsHandle +local termStreak = 0 +local termStreakAt = 0 +local lastPlrList +--#endregion + +--#region Init/event Helpers +local function connectToLink() + http.websocketAsync(cfg.linkToWS) +end +local function scheduleScan() + os.startTimer(2) +end +--#endregion + +--#region Helpers +local function dispatchLink(mtag, cont, data) + if not wsHandle then + return + end + + local msg = { + Tag = mtag, + [cont] = data, + } + local jmsg = textutils.serialiseJSON(msg) + wsHandle.send(jmsg) +end +--#endregion + +--#region Command Handling local function nextWord(str) local first, last @@ -31,7 +63,18 @@ local function nextWord(str) end local function processMessage(unm, msg, hidden) - if not hidden and msg:sub(1, #cfg.prefix) ~= cfg.prefix then return end + if not hidden and msg:sub(1, #cfg.prefix) ~= cfg.prefix then + -- it isn't smth we care about so let's broadcast? + if not cfg.sendToLink then + -- no let's not + return + end + dispatchLink( + "on_minecraft_chat", "OnMinecraftChat", + { Sender = unm, Content = msg } + ) + return + end if not hidden then msg = msg:sub(#cfg.prefix + 1) @@ -40,12 +83,6 @@ local function processMessage(unm, msg, hidden) local cmd msg, cmd = nextWord(msg) - local user = cfg.users[unm] - if user == nil then - ch.reportLog("foreign user " .. unm .. " tries: " .. cmd) - return - end - local xcmd for k, v in next, cmds do if k == cmd then @@ -59,6 +96,18 @@ local function processMessage(unm, msg, hidden) end end end + + local user = cfg.users[unm] + if user == nil then + if xcmd.allowAnybody then + -- prevent nil index w/ dummy user + user = {} + else + ch.reportLog("foreign user " .. unm .. " tries: " .. cmd) + return + end + end + if not xcmd then ch.reportLog("user " .. unm .. " tries invalid cmd: " .. cmd) ch.send(unm, "not a valid command", "cmd") @@ -113,6 +162,26 @@ local function processMessage(unm, msg, hidden) return end end + elseif x.match == "boolean" then + msg, arg = nextWord(msg) + if not arg and x.optional then + arg = "f" + else + arg = (arg or ""):lower() + + if arg == "true" or arg == "t" or + arg == "yes" or arg == "y" or + arg == "on" or arg == "1" then + arg = true + elseif arg == "false" or arg == "f" or + arg == "no" or arg == "n" or + arg == "off" or arg == "0" then + arg = false + else + ch.send(unm, "invalid boolean for: " .. x.desc, "cmd") + return + end + end else -- what?? return true, error("invalid match type") @@ -129,16 +198,13 @@ local function processMessage(unm, msg, hidden) return true end end +--#endregion --- local function scheduleScan() --- os.startTimer(2) --- end - -local termStreak = 0 -local termStreakAt = 0 --- local lastPlrList local listeners = { ["chat"] = function(username, message, uuid, isHidden) + if not ch.checkDebounce(username, message, uuid, isHidden) then + return + end return processMessage(username, message, isHidden) end, ["playerChangedDimension"] = function(username, fromDim, toDim) @@ -150,23 +216,48 @@ local listeners = { ["playerLeave"] = function(username, dimension) tk.plrs[username] = nil end, - -- ["timer"] = function() - -- scheduleScan() + ["websocket_success"] = function(url, handle) + wsHandle = handle + ch.reportLog("connected!", "link") + end, + ["websocket_failure"] = function(url, err) + ch.reportLog("connection failed", "link") + end, + ["websocket_message"] = function(url, data, isBinary) + local msg = textutils.unserialiseJSON(data) + if not msg then return end - -- local plrs = tk:scanRange(16) - -- table.sort(plrs) + if msg.Tag == "on_discord_chat" then + local p = msg.OnDiscordChat + if not p then return end + local sender, content = p.SenderNickname, p.Content + if not sender or not content then return end - -- local plrList = table.concat(plrs, ", ") - -- if plrList ~= lastPlrList then - -- if #plrs > 0 then - -- ch.reportLog("players in range: " .. plrList, "scan") - -- elseif lastPlrList ~= nil then - -- ch.reportLog("players left range", "scan") - -- end + ch.saysquare("@" .. sender, content) + end + end, + ["websocket_closed"] = function(url, reason, code) + ch.reportLog("disconnected", "link") + wsHandle = nil + connectToLink() + end, + ["timer"] = function() + scheduleScan() - -- lastPlrList = plrList - -- end - -- end, + local plrs = tk:scanRange(16) + table.sort(plrs) + + local plrList = table.concat(plrs, ", ") + if plrList ~= lastPlrList then + if #plrs > 0 then + ch.reportLog("players in range: " .. plrList, "scan") + elseif lastPlrList ~= nil then + ch.reportLog("players left range", "scan") + end + + lastPlrList = plrList + end + end, ["peripheral_detach"] = function() end, ["terminate"] = function() @@ -203,8 +294,14 @@ local function evDispatcher() end end +tk:refresh() + ch.userBc("Loaded!") ch.reportLog("you are auto subbed to log, welcome!") -tk:refresh() +if cfg.linkToWS ~= nil then + connectToLink() +end + +scheduleScan() evDispatcher() diff --git a/tracking.lua b/tracking.lua index c945a99..e65107c 100644 --- a/tracking.lua +++ b/tracking.lua @@ -3,8 +3,7 @@ local levenshtein = require("levenshtein") local pd = peripheral.find("player_detector") if not pd then - print("no player detector :(") - return + error("no player detector :(") end local tk = {}