308 lines
7.9 KiB
Lua
308 lines
7.9 KiB
Lua
-- Skynet v1.3 // server
|
|
-- orig. written by minish - 2023-10
|
|
-- revived 2025-01
|
|
|
|
--#region Imports
|
|
local cfg = require("cfg")
|
|
local ch = require("chat")
|
|
local tk = require("tracking")
|
|
local cmds = require("cmds")
|
|
--#endregion
|
|
|
|
--#region Machine Preparation
|
|
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
|
|
|
|
if str:sub(1, 1) == "[" then
|
|
str = str:sub(2)
|
|
first, last = str:find("[^]]+")
|
|
else
|
|
first, last = str:find("%S+")
|
|
end
|
|
|
|
if not last then
|
|
return str, nil
|
|
end
|
|
|
|
return str:sub(last + 2), str:sub(first, last)
|
|
end
|
|
|
|
local function processMessage(unm, msg, hidden)
|
|
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)
|
|
end
|
|
|
|
local cmd
|
|
msg, cmd = nextWord(msg)
|
|
|
|
local xcmd
|
|
for k, v in next, cmds do
|
|
if k == cmd then
|
|
xcmd = v
|
|
break
|
|
end
|
|
for _, a in next, v.alias do
|
|
if a == cmd then
|
|
xcmd = v
|
|
break
|
|
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")
|
|
return
|
|
end
|
|
|
|
if user.limited and not xcmd.allowLimitedUser then
|
|
ch.reportLog("limited user " .. unm .. " tries: " .. cmd)
|
|
return
|
|
end
|
|
|
|
if xcmd.requireAdminPrivilege and not user.admin then
|
|
ch.reportLog("non-admin user " .. unm .. " attempted to " .. cmd)
|
|
ch.send(unm, "no permission to do that..", "cmd")
|
|
return
|
|
end
|
|
|
|
local args = {}
|
|
|
|
for _, x in next, xcmd.args do
|
|
local arg
|
|
|
|
if x.match == "block" then
|
|
msg, arg = nextWord(msg)
|
|
if not arg and not x.optional then
|
|
ch.send(unm, "missing arg: " .. x.desc, "cmd")
|
|
return
|
|
end
|
|
elseif x.match == "player" then
|
|
msg, arg = nextWord(msg)
|
|
if not arg and not x.optional then
|
|
ch.send(unm, "missing player arg: " .. x.desc, "cmd")
|
|
return
|
|
else
|
|
arg = tk:resTg(arg)
|
|
if not arg then
|
|
ch.send(unm, "target not found for: " .. x.desc, "cmd")
|
|
return
|
|
end
|
|
end
|
|
elseif x.match == "rest" then
|
|
arg = msg
|
|
msg = ""
|
|
elseif x.match == "number" then
|
|
msg, arg = nextWord(msg)
|
|
if not arg and x.optional then
|
|
arg = nil
|
|
else
|
|
arg = tonumber(arg)
|
|
if not arg then
|
|
ch.send(unm, "invalid number for: " .. x.desc, "cmd")
|
|
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")
|
|
end
|
|
|
|
table.insert(args, arg)
|
|
end
|
|
|
|
ch.reportLog("user " .. unm .. " runs: " .. cmd)
|
|
local res = xcmd.proc(unm, table.unpack(args))
|
|
|
|
if res then
|
|
-- command requested shutdown
|
|
return true
|
|
end
|
|
end
|
|
--#endregion
|
|
|
|
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)
|
|
ch.reportLog(username .. " goes from " .. fromDim .. " to " .. toDim, "dims")
|
|
end,
|
|
["playerJoin"] = function(username, dimension)
|
|
tk.plrs[username] = { dimension = dimension }
|
|
end,
|
|
["playerLeave"] = function(username, dimension)
|
|
tk.plrs[username] = nil
|
|
end,
|
|
["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
|
|
|
|
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
|
|
|
|
ch.saysquare("@" .. sender, content)
|
|
end
|
|
end,
|
|
["websocket_closed"] = function(url, reason, code)
|
|
ch.reportLog("disconnected", "link")
|
|
wsHandle = nil
|
|
connectToLink()
|
|
end,
|
|
["timer"] = function()
|
|
scheduleScan()
|
|
|
|
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()
|
|
-- should we reset term streak
|
|
if os.clock() - termStreakAt > 1 then
|
|
-- yes
|
|
termStreak = 1
|
|
termStreakAt = os.clock()
|
|
else
|
|
-- no so increase streak
|
|
termStreak = termStreak + 1
|
|
end
|
|
|
|
-- check if streak is too much
|
|
if termStreak >= 2 then
|
|
ch.reportLog("restarting to prevent sys access..")
|
|
os.reboot()
|
|
end
|
|
|
|
print("?")
|
|
ch.reportLog("ALERT!! somebody tried to terminate skynet runner")
|
|
end,
|
|
}
|
|
|
|
local function evDispatcher()
|
|
while true do
|
|
local params = { os.pullEventRaw() }
|
|
local event = table.remove(params, 1)
|
|
local listener = listeners[event]
|
|
|
|
if listener and listener(table.unpack(params)) then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
tk:refresh()
|
|
|
|
ch.userBc("Loaded!")
|
|
ch.reportLog("you are auto subbed to log, welcome!")
|
|
|
|
if cfg.linkToWS ~= nil then
|
|
connectToLink()
|
|
end
|
|
|
|
scheduleScan()
|
|
evDispatcher()
|