mods that hopefully work for a TechAge-based pack

This commit is contained in:
2026-09-09 06:27:51 -06:00
parent 4e6b08d194
commit c27db2a537
6234 changed files with 375578 additions and 0 deletions
@@ -0,0 +1,250 @@
--[[
Techage
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
commands.lua:
Register all basic controller commands
]]--
-- store protection data locally
local LocalRef = {}
local function not_protected(owner, numbers)
if owner and numbers then
LocalRef[owner] = LocalRef[owner] or {}
if LocalRef[owner][numbers] == nil then
LocalRef[owner][numbers] = techage.check_numbers(numbers, owner)
end
return LocalRef[owner][numbers]
end
return false
end
techage.lua_ctlr.register_function("get_input", {
cmnd = function(self, num)
num = tostring(num or "")
return techage.lua_ctlr.get_input(self.meta.number, num)
end,
help = ' $get_input(num) --> "on", "off", or nil\n'..
' Read local input value from device with number "num".\n'..
' example: inp = $get_input("1234")\n'..
" The device has to be connected with the controller."
})
techage.lua_ctlr.register_function("get_next_input", {
cmnd = function(self)
return techage.lua_ctlr.get_next_input(self.meta.number)
end,
help = ' $get_next_input() --> number and state\n'..
' Similar to $get_input(), but provides the\n'..
' input node number in addition.\n'..
' example: num, state = $get_next_input()\n'..
' This function deletes the input and returns\n'..
' nil if no further input value is available.'
})
techage.lua_ctlr.register_function("read_data", {
cmnd = function(self, num, cmnd, data)
num = tostring(num or "")
cmnd = tostring(cmnd or "")
if not_protected(self.meta.owner, num) then
return techage.send_single(self.meta.number, num, cmnd, data)
end
end,
help = " $read_data(num, cmnd, add_data)\n"..
" This function is deprecated.\n"..
" It will be removed in future releases.\n"..
" Use $send_cmnd(num, cmnd, add_data) instead."
})
techage.lua_ctlr.register_function("time_as_str", {
cmnd = function(self)
local t = minetest.get_timeofday()
local h = math.floor(t*24) % 24
local m = math.floor(t*1440) % 60
return string.format("%02d:%02d", h, m)
end,
help = " $time_as_str() --> e.g. '18:45'\n"..
" Read time of day as string (24h).\n"..
' example: time = $time_as_str()'
})
techage.lua_ctlr.register_function("time_as_num", {
cmnd = function(self, num)
local t = minetest.get_timeofday()
local h = math.floor(t*24) % 24
local m = math.floor(t*1440) % 60
return h * 100 + m
end,
help = " $time_as_num() --> e.g.: 1845\n"..
" Read time of day as number (24h).\n"..
' example: time = $time_as_num()'
})
techage.lua_ctlr.register_action("send_cmnd", {
cmnd = function(self, num, cmnd, data)
num = tostring(num or "")
cmnd = tostring(cmnd or "")
if not_protected(self.meta.owner, num) then
return techage.send_single(self.meta.number, num, cmnd, data)
end
end,
help = " $send_cmnd(num, cmnd, add_data)\n"..
' Send a command to the device with number "num".\n'..
' "cmnd" is the command as text string\n'..
' "add_data" is additional data (optional)\n'..
' example: $send_cmnd("1234", "on")'
})
techage.lua_ctlr.register_action("set_filter", {
cmnd = function(self, num, slot, val)
num = tostring(num or "")
slot = tostring(slot or "red")
val = tostring(val or "on")
if not_protected(self.meta.owner, num) then
techage.send_single(self.meta.number, num, "port", slot.."="..val)
end
end,
help = " $set_filter(num, slot, val)\n"..
' Turn on/off a Distributor filter slot.\n'..
' example: $set_filter("1234", "red", "off")'
})
techage.lua_ctlr.register_action("get_filter", {
cmnd = function(self, num, slot)
num = tostring(num or "")
slot = tostring(slot or "red")
if not_protected(self.meta.owner, num) then
return techage.send_single(self.meta.number, num, "port", slot)
end
end,
help = " $get_filter(num, slot)\n"..
' Read state of a Distributor filter slot.\n'..
' Return value is "on" or "off".\n'..
' example: state = $get_filter("1234", "red")'
})
techage.lua_ctlr.register_action("display", {
cmnd = function(self, num, row, text)
num = tostring(num or "")
row = tonumber(row or 1) or 1
text = tostring(text or "")
if not_protected(self.meta.owner, num) then
if text:byte(1) == 32 then -- left aligned?
-- use the '\t' lcdlib control char for left-aligned
text = "\t" .. text:sub(2)
end
if row == 0 then -- add line?
techage.send_single(self.meta.number, num, "add", text)
else
local payload = safer_lua.Store()
payload.set("row", row)
payload.set("str", text)
techage.send_single(self.meta.number, num, "set", payload)
end
end
end,
help = " $display(num, row, text)\n"..
' Send a text line to the display with number "num".\n'..
" 'row' is a value from 1..5, or 0 for scroll screen\n"..
" and add a new line. If the first char of the string\n"..
" is a blank, the text will be horizontally centered.\n"..
' example: $display("123", 1, "Hello "..name)'
})
techage.lua_ctlr.register_action("display2", {
cmnd = function(self, num, row, text)
num = tostring(num or "")
row = tonumber(row or 1) or 1
text = tostring(text or "")
if not_protected(self.meta.owner, num) then
if row == 0 then -- add line?
techage.send_single(self.meta.number, num, "add", text)
else
local payload = safer_lua.Store()
payload.set("row", row)
payload.set("str", text)
techage.send_single(self.meta.number, num, "set", payload)
end
end
end,
help = " $display2(num, row, text)\n"..
" Alternative 'display' function with different\n"..
" control char. If the first char of the string\n"..
" is a '\t', the text will be horizontally centered."
})
techage.lua_ctlr.register_action("clear_screen", {
cmnd = function(self, num)
num = tostring(num or "")
if not_protected(self.meta.owner, num) then
techage.send_single(self.meta.number, num, "clear", nil)
end
end,
help = " $clear_screen(num)\n"..
' Clear the screen of the display\n'..
' with number "num".\n'..
' example: $clear_screen("1234")'
})
techage.lua_ctlr.register_action("chat", {
cmnd = function(self, text)
text = tostring(text or "")
minetest.chat_send_player(self.meta.owner, "[TA4 Lua Controller] "..text)
end,
help = " $chat(text,...)\n"..
" Send yourself a chat message.\n"..
' example: $chat("Hello "..name)'
})
techage.lua_ctlr.register_action("door", {
cmnd = function(self, pos, text)
pos = tostring(pos or "")
text = tostring(text or "")
pos = minetest.string_to_pos("("..pos..")")
if pos then
local door = doors.get(pos)
if door then
local player = {
get_player_name = function() return self.meta.owner end,
is_player = function() return true end,
}
if text == "open" then
door:open(player)
elseif text == "close" then
door:close(player)
end
end
end
end,
help = " $door(pos, text)\n"..
' Open/Close a door at position "pos"\n'..
' example: $door("123,7,-1200", "close")\n'..
" Hint: Use the Techage Programmer to\ndetermine the door position."
})
techage.lua_ctlr.register_function("item_description", {
cmnd = function(self, itemstring)
local item_def = minetest.registered_items[itemstring]
if item_def and item_def.description then
return minetest.get_translated_string("en", item_def.description)
end
return ""
end,
help = " $item_description(itemstring)\n"..
" Get the description for a specified itemstring.\n"..
' example: desc = $item_description("default:apple")'
})
-- function not_protected(owner, number(s))
techage.lua_ctlr.not_protected = not_protected
@@ -0,0 +1,625 @@
--[[
TechAge
=======
Copyright (C) 2019-2025 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Lua Controller
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local M = minetest.get_meta
local sHELP = [[TA4 Lua Controller
This controller is used to control and monitor
TechAge machines.
This controller can be programmed in Lua.
See on GitHub for more help:
https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md
or download the PDF file from:
https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.pdf
]]
techage.lua_ctlr = {}
local Cache = {}
local STATE_STOPPED = 0
local STATE_RUNNING = 1
local CYCLE_TIME = 1
local CREDITS = 10
local MAX_CREDITS = 100
local tCommands = {}
local tFunctions = {" Overview", " Data structures"}
local tHelpTexts = {[" Overview"] = sHELP, [" Data structures"] = safer_lua.DataStructHelp}
local sFunctionList = ""
local tFunctionIndex = {}
local MaxCodeSize = tonumber(minetest.settings:get("techage_luacontroller_max_code_size")) or safer_lua.MaxCodeSize * 4
local MaxTableSize = tonumber(minetest.settings:get("techage_luacontroller_max_table_size")) or safer_lua.MaxTableSize
local SlotExeTime = tonumber(minetest.settings:get("techage_luacontroller_slot_exe_time")) or 200
safer_lua.config(MaxCodeSize, MaxTableSize, safer_lua.MaxExeTime * 10)
minetest.after(2, function()
sFunctionList = table.concat(tFunctions, ",")
for idx,key in ipairs(tFunctions) do
tFunctionIndex[key] = idx
end
end)
local function output(pos, text)
local meta = M(pos)
text = meta:get_string("output") .. "\n" .. (text or "")
text = text:sub(-500,-1)
meta:set_string("output", text)
end
--
-- API functions for function/action registrations
--
function techage.lua_ctlr.register_function(key, attr)
tCommands[key] = attr.cmnd
table.insert(tFunctions, " $"..key)
tHelpTexts[" $"..key] = attr.help
end
function techage.lua_ctlr.register_action(key, attr)
tCommands[key] = attr.cmnd
table.insert(tFunctions, " $"..key)
tHelpTexts[" $"..key] = attr.help
end
local function merge(dest, keys, values)
for idx,key in ipairs(keys) do
dest.env[key] = values[idx]
end
return dest
end
local function restart_timer(pos, cycletime)
minetest.get_node_timer(pos):stop()
if cycletime > 0 then
minetest.get_node_timer(pos):start(cycletime)
end
end
techage.lua_ctlr.register_action("print", {
cmnd = function(self, text)
local pos = self.meta.pos
text = tostring(text or "")
output(pos, text)
--print("Lua: "..text)
end,
help = " $print(text)\n"..
" Send a text line to the output window.\n"..
' e.g. $print("Hello "..name)'
})
techage.lua_ctlr.register_action("loopcycle", {
cmnd = function(self, cycletime)
cycletime = math.floor(tonumber(cycletime) or 0)
local pos = self.meta.pos
minetest.after(0, restart_timer, pos, cycletime)
end,
help = "$loopcycle(seconds)\n"..
" This function allows to change the\n"..
" call frequency of the loop() function.\n"..
" value is in seconds, 0 = disable\n"..
' e.g. $loopcycle(10)'
})
techage.lua_ctlr.register_action("events", {
cmnd = function(self, event)
self.meta.events = event or false
end,
help = "$events(true/false)\n"..
" Enable/disable event handling.\n"..
' e.g. $events(true) -- enable events'
})
techage.lua_ctlr.register_function("get_ms_time", {
cmnd = function(self)
return math.floor(minetest.get_us_time() / 1000)
end,
help = " ms = $get_ms_time()\n"..
" returns time with millisecond precision."
})
techage.lua_ctlr.register_function("get_gametime", {
cmnd = function(self)
return minetest.get_gametime()
end,
help = " t = $get_gametime()\n"..
" returns the time, in seconds, since the world was created."
})
techage.lua_ctlr.register_function("position", {
cmnd = function(self, number)
local info = techage.get_node_info(number)
if info then
return S(info.pos)
end
return "(-,-,-)"
end,
help = " pos = $position(number)\n"..
" returns the position '(x,y,z)' of the device\n with given number."
})
local function formspec1(meta)
local state = meta:get_int("state") == techage.RUNNING
local cmnd = state and "stop;Stop" or "start;Start"
local init = meta:get_string("init")
init = minetest.formspec_escape(init)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"..
"tabheader[0,0;tab;init,func,loop,outp,notes,help;1;;true]"..
"textarea[0.3,0.2;10,8.3;init;function init();"..init.."]"..
"background[0.1,0.3;9.8,7.0;techage_form_mask.png]"..
"label[0,7.3;end]"..
"button_exit[4.4,7.5;1.8,1;cancel;Cancel]"..
"button[6.3,7.5;1.8,1;save;Save]"..
"button[8.2,7.5;1.8,1;"..cmnd.."]"
end
local function formspec2(meta)
local state = meta:get_int("state") == techage.RUNNING
local cmnd = state and "stop;Stop" or "start;Start"
local func = meta:get_string("func")
func = minetest.formspec_escape(func)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"..
"tabheader[0,0;tab;init,func,loop,outp,notes,help;2;;true]"..
"textarea[0.3,0.2;10,8.3;func;functions:;"..func.."]"..
"background[0.1,0.3;9.8,7.0;techage_form_mask.png]"..
"button_exit[4.4,7.5;1.8,1;cancel;Cancel]"..
"button[6.3,7.5;1.8,1;save;Save]"..
"button[8.2,7.5;1.8,1;"..cmnd.."]"
end
local function formspec3(meta)
local state = meta:get_int("state") == techage.RUNNING
local cmnd = state and "stop;Stop" or "start;Start"
local loop = meta:get_string("loop")
loop = minetest.formspec_escape(loop)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"..
"tabheader[0,0;tab;init,func,loop,outp,notes,help;3;;true]"..
"textarea[0.3,0.2;10,8.3;loop;function loop(ticks, elapsed);"..loop.."]"..
"background[0.1,0.3;9.8,7.0;techage_form_mask.png]"..
"label[0,7.3;end]"..
"button_exit[4.4,7.5;1.8,1;cancel;Cancel]"..
"button[6.3,7.5;1.8,1;save;Save]"..
"button[8.2,7.5;1.8,1;"..cmnd.."]"
end
local function formspec4(meta)
local state = meta:get_int("state") == techage.RUNNING
local cmnd = state and "stop;Stop" or "start;Start"
local output = meta:get_string("output")
output = minetest.formspec_escape(output)
output = output:gsub("\n", ",")
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"tabheader[0,0;tab;init,func,loop,outp,notes,help;4;;true]"..
"table[0.2,0.2;9.5,7;output;"..output..";200]"..
"button[4.4,7.5;1.8,1;clear;Clear]"..
"button[6.3,7.5;1.8,1;update;Update]"..
"button[8.2,7.5;1.8,1;"..cmnd.."]"
end
local function formspec5(meta)
local notes = meta:get_string("notes")
notes = minetest.formspec_escape(notes)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"..
"tabheader[0,0;tab;init,func,loop,outp,notes,help;5;;true]"..
"textarea[0.3,0.2;10,8.3;notes;Notepad:;"..notes.."]"..
"background[0.1,0.3;9.8,7.0;techage_form_mask.png]"..
"button_exit[6.3,7.5;1.8,1;cancel;Cancel]"..
"button[8.2,7.5;1.8,1;save;Save]"
end
local function formspec6(items, pos, text)
text = minetest.formspec_escape(text)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"style_type[textarea;font=mono;textcolor=#FFFFFF]"..
"tabheader[0,0;tab;init,func,loop,outp,notes,help;6;;true]"..
"label[0,-0.2;Functions:]"..
"dropdown[0.3,0.2;10,8.3;functions;"..items..";"..pos.."]"..
"textarea[0.3,1.3;10,8;help;Help:;"..text.."]"
end
local function patch_error_string(err, line_offs)
local tbl = {}
for s in err:gmatch("[^\r\n]+") do
if s:find("loop:(%d+):") then
local prefix, line, err = s:match("(.-)loop:(%d+):(.+)")
if prefix and line and err then
if tonumber(line) < line_offs then
table.insert(tbl, prefix.."func:"..line..":"..err)
else
line = tonumber(line) - line_offs
table.insert(tbl, prefix.."loop:"..line..":"..err)
end
end
else
table.insert(tbl, s)
end
end
return table.concat(tbl, "\n")
end
-- Credit-based runtime environment
local function add_credits(number, credits)
local tbl = Cache[number]
tbl.credits = (tbl.credits or 0) + math.floor(credits + 0.5)
if tbl.credits > MAX_CREDITS then
tbl.credits = MAX_CREDITS
end
if tbl.credits < -MAX_CREDITS then
tbl.credits = MAX_CREDITS
end
return tbl.credits
end
local function get_credits(number)
return Cache[number].credits or 0
end
local function error(pos, err)
local meta = M(pos)
local func = meta:get_string("func")
local _,line_offs = string.gsub(func, "\n", "\n")
line_offs = line_offs + 1
err = patch_error_string(err, line_offs)
output(pos, err)
local number = meta:get_string("number")
meta:set_string("infotext", "Controller "..number..": error")
meta:set_int("state", techage.STOPPED)
meta:set_string("formspec", formspec4(meta))
minetest.get_node_timer(pos):stop()
return false
end
local function compile(pos, meta, number)
local init = meta:get_string("init")
local func = meta:get_string("func")
local loop = meta:get_string("loop")
local owner = meta:get_string("owner")
local env = table.copy(tCommands)
env.meta = {pos=pos, owner=owner, number=number, error=error}
local code = safer_lua.init(pos, init, func.."\n"..loop, env, error)
if code then
Cache[number] = {code=code, inputs={}, events=env.meta.events}
Cache[number].inputs.term = nil -- terminal inputs
Cache[number].inputs.msg = {} -- message queue
Cache[number].credits = MAX_CREDITS
return true
end
return false
end
local function start_controller(pos)
local meta = M(pos)
local number = meta:get_string("number")
meta:set_string("output", "")
if compile(pos, meta, number) then
meta:set_int("state", techage.RUNNING)
minetest.get_node_timer(pos):start(CYCLE_TIME)
meta:set_string("formspec", formspec4(meta))
meta:set_string("infotext", "Controller "..number..": running")
return true
end
return false
end
local function stop_controller(pos)
local meta = M(pos)
local number = meta:get_string("number")
meta:set_int("state", techage.STOPPED)
minetest.get_node_timer(pos):stop()
meta:set_string("infotext", "Controller "..number..": stopped")
meta:set_string("formspec", formspec3(meta))
end
local function call_loop(pos, elapsed)
local meta = M(pos)
local number = meta:get_string("number")
if meta:get_int("state") == techage.RUNNING then
if Cache[number] or compile(pos, meta, number) then
Cache[number].event_pending = false
local dt = minetest.get_gametime() - (Cache[number].last_time or 0)
local credits = add_credits(number, CREDITS * dt)
Cache[number].last_time = minetest.get_gametime()
if credits > 0 then
local code = Cache[number].code
local t = minetest.get_us_time()
local res = safer_lua.run_loop(pos, elapsed, code, error)
-- Consider the time used for running the code and calculate the credits spent
local spent = math.floor((minetest.get_us_time() - t) / SlotExeTime) -- in credits
add_credits(number, -spent)
local state = res and "running" or "stopped"
meta:set_string("infotext", "Controller "..number..": "..state.." ("..credits.." credits)")
return res
end
meta:set_string("infotext", "Controller "..number..": running ("..credits.." credits)")
return true
end
end
return false
end
local function on_timer(pos, elapsed)
if techage.is_activeformspec(pos) then
local meta = M(pos)
meta:set_string("formspec", formspec4(meta))
end
return call_loop(pos, elapsed, CREDITS)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
--print(dump(fields))
techage.reset_activeformspec(pos, player)
if fields.cancel == nil then
if fields.init then
meta:set_string("init", fields.init)
meta:set_string("formspec", formspec1(meta))
elseif fields.func then
meta:set_string("func", fields.func)
meta:set_string("formspec", formspec2(meta))
elseif fields.loop then
meta:set_string("loop", fields.loop)
meta:set_string("formspec", formspec3(meta))
elseif fields.notes then
meta:set_string("notes", fields.notes)
meta:set_string("formspec", formspec5(meta))
end
end
if fields.update then
meta:set_string("formspec", formspec4(meta))
techage.set_activeformspec(pos, player)
elseif fields.clear then
meta:set_string("output", "<press update>")
meta:set_string("formspec", formspec4(meta))
elseif fields.tab == "1" then
meta:set_string("formspec", formspec1(meta))
elseif fields.tab == "2" then
meta:set_string("formspec", formspec2(meta))
elseif fields.tab == "3" then
meta:set_string("formspec", formspec3(meta))
elseif fields.tab == "4" then
techage.set_activeformspec(pos, player)
meta:set_string("formspec", formspec4(meta))
elseif fields.tab == "5" then
meta:set_string("formspec", formspec5(meta))
elseif fields.tab == "6" then
meta:set_string("formspec", formspec6(sFunctionList, 1, sHELP))
elseif fields.start == "Start" then
start_controller(pos)
minetest.log("action", player:get_player_name() ..
" starts the sl_controller at ".. minetest.pos_to_string(pos))
elseif fields.stop == "Stop" then
stop_controller(pos)
elseif fields.functions then
local key = fields.functions
local text = tHelpTexts[key] or ""
local pos = tFunctionIndex[key] or 1
meta:set_string("formspec", formspec6(sFunctionList, pos, text))
end
end
minetest.register_node("techage:ta4_lua_controller", {
description = "TA4 Lua Controller",
inventory_image = "techage_lua_controller_inventory.png",
wield_image = "techage_lua_controller_inventory.png",
stack_max = 1,
tiles = {
-- up, down, right, left, back, front
"techage_smartline.png",
"techage_smartline.png",
"techage_smartline.png",
"techage_smartline.png",
"techage_smartline.png",
"techage_smartline.png^techage_lua_controller.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
},
},
after_place_node = function(pos, placer)
local meta = M(pos)
local number = techage.add_node(pos, "techage:ta4_lua_controller")
meta:set_string("owner", placer:get_player_name())
meta:set_string("number", number)
meta:set_int("state", techage.STOPPED)
meta:set_string("init", "-- called only once")
meta:set_string("func", "-- for your functions")
meta:set_string("loop", "-- called every second")
meta:set_string("notes", "For your notes / snippets")
meta:mark_as_private("init")
meta:mark_as_private("func")
meta:mark_as_private("loop")
meta:mark_as_private("notes")
meta:set_string("formspec", formspec1(meta))
meta:set_string("infotext", "Controller "..number..": stopped")
end,
on_receive_fields = on_receive_fields,
on_rightclick = function(pos, node, clicker)
local meta = M(pos)
if meta:get_int("state") == techage.RUNNING then
techage.set_activeformspec(pos, clicker)
meta:set_string("formspec", formspec4(meta))
end
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end,
on_timer = on_timer,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=1, cracky=1, crumbly=1},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
minetest.register_craft({
output = "techage:ta4_lua_controller",
recipe = {
{"basic_materials:plastic_sheet", "dye:blue", "techage:aluminum"},
{"", "default:copper_ingot", ""},
{"techage:ta4_ramchip", "techage:ta4_wlanchip", "techage:ta4_ramchip"},
},
})
-- write inputs from remote nodes
local function set_input(pos, number, input, val)
if input and M(pos):get_int("state") == techage.RUNNING then
if (Cache[number] or compile(pos, M(pos), number)) and Cache[number].inputs then
if input == "msg" then
if #Cache[number].inputs["msg"] < 10 then
table.insert(Cache[number].inputs["msg"], val)
end
else
Cache[number].inputs[input] = val
end
if Cache[number].events and not Cache[number].event_pending then -- events enabled
Cache[number].event_pending = true
minetest.after(0, call_loop, pos, -1, CREDITS)
end
end
end
end
-- used by the command "input"
function techage.lua_ctlr.get_input(number, input)
if input then
if Cache[number] and Cache[number].inputs then
return Cache[number].inputs[input] or "off"
end
end
return "off"
end
function techage.lua_ctlr.get_next_input(number)
if Cache[number] and Cache[number].inputs then
local num, state = next(Cache[number].inputs or {})
if num ~= "msg" and num ~= "term" then
if num then
Cache[number].inputs[num] = nil
end
return num, state
end
end
end
-- used for Terminal commands
function techage.lua_ctlr.get_command(number)
if Cache[number] and Cache[number].inputs then
local cmnd = Cache[number].inputs["term"]
Cache[number].inputs["term"] = nil
return cmnd
end
end
-- used for queued messages
function techage.lua_ctlr.get_msg(number)
if Cache[number] and Cache[number].inputs then
return table.remove(Cache[number].inputs["msg"], 1)
end
end
techage.register_node({"techage:ta4_lua_controller"}, {
on_recv_message = function(pos, src, topic, payload)
local meta = M(pos)
local number = meta:get_string("number")
if topic == "on" then
set_input(pos, number, src, topic)
elseif topic == "off" then
set_input(pos, number, src, topic)
elseif topic == "term" then
set_input(pos, number, "term", payload)
elseif topic == "msg" then
set_input(pos, number, "msg", {src = src, data = payload})
elseif topic == "state" then
local state = meta:get_int("state") or techage.STOPPED
return techage.StateStrings[state] or "stopped"
else
return "unsupported"
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
local meta = M(pos)
local number = meta:get_string("number")
if topic == 1 and payload[1] == 1 then
set_input(pos, number, src, "on")
elseif topic == 1 and payload[1] == 0 then
set_input(pos, number, src, "off")
else
return 2
end
return 0
end,
on_beduino_request_data = function(pos, src, topic, payload)
local meta = M(pos)
if topic == 142 then
local state = meta:get_int("stage") == techage.RUNNING and STATE_RUNNING or STATE_STOPPED
return 0, {state}
else
return 2, ""
end
end,
})
@@ -0,0 +1,276 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Sensor Chest
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local PlayerActions = {}
local InventoryState = {}
local function store_action(pos, player, action)
local meta = minetest.get_meta(pos)
local name = player and player:get_player_name() or ""
local number = meta:get_string("node_number")
PlayerActions[number] = {name, action}
end
local function send_off_command(pos)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
if number ~= "" then
local own_num = meta:get_string("node_number")
techage.send_single(own_num, number, "off")
end
end
local function send_command(pos)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
if number ~= "" then
local own_num = meta:get_string("node_number")
techage.send_single(own_num, number, "on")
minetest.after(0.2, send_off_command, pos)
end
end
local function get_stack(pos, idx)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack("main", idx)
return stack:get_name(), stack:get_count()
end
local function get_stacks(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local a = safer_lua.Array()
for idx = 1,4 do
local stack = inv:get_stack("main", idx)
local s = safer_lua.Store()
if stack:get_count() > 0 then
s.set("name", stack:get_name())
s.set("count", stack:get_count())
a.add(s)
end
end
return a
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if M(pos):get_string("public") ~= "true" and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
store_action(pos, player, "put")
send_command(pos)
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if M(pos):get_string("public") ~= "true" and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
store_action(pos, player, "take")
send_command(pos)
return stack:get_count()
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = minetest.get_meta(pos):get_inventory()
return inv:is_empty("main")
end
local function after_dig_node(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
end
local function formspec1()
return "size[5.5,4]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"field[0.5,1;5,1;number;TA4 Lua Controller number:;]" ..
"checkbox[0.5,1.8;public;"..S("Allow public chest access")..";false]"..
"button_exit[1.7,2.8;2,1;exit;Save]"
end
local function formspec2(pos)
local text = M(pos):get_string("text")
return "size[8,6]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;main;0,0;2,2;]"..
"button[2,0;1,1;f1;F1]"..
"button[2,1;1,1;f2;F2]"..
"label[3,0;"..text.."]"..
"list[current_player;main;0,2.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
minetest.register_node("techage:ta4_sensor_chest", {
description = S("TA4 Sensor Chest"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png^techage_appl_sensor.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png^techage_appl_sensor.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png^techage_appl_sensor.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_front_ta4.png^techage_appl_sensor.png",
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('main', 4)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local number = techage.add_node(pos, "techage:ta4_sensor_chest")
meta:set_string("node_number", number)
meta:set_string("owner", placer:get_player_name())
meta:set_string("text", "Text to be changed\nby command.")
meta:set_string("formspec", formspec1())
meta:set_string("infotext", S("TA4 Sensor Chest").." "..number..": "..S("not connected"))
end,
on_receive_fields = function(pos, formname, fields, player)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if meta:get_string("public") ~= "true" and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if fields.public then
meta:set_string("public", fields.public)
end
if fields.quit == "true" and fields.number and fields.number ~= "" then
local owner = meta:get_string("owner")
if techage.check_numbers(fields.number, owner) then
meta:set_string("number", fields.number)
local node_number = meta:get_string("node_number")
meta:set_string("infotext", S("TA4 Sensor Chest").." "..node_number..": "..S("connected with").." "..fields.number)
meta:set_string("formspec", formspec2(pos))
end
elseif fields.f1 then
store_action(pos, player, "f1")
send_command(pos)
meta:set_string("formspec", formspec2(pos))
elseif fields.f2 then
store_action(pos, player, "f2")
send_command(pos)
meta:set_string("formspec", formspec2(pos))
end
end,
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, S("TA4 Sensor Chest"))
end,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta4_sensor_chest"}, {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_inv_state(inv, "main")
elseif topic == "action" then
local meta = minetest.get_meta(pos)
local number = meta:get_string("node_number")
return (PlayerActions[number] or {})[1], (PlayerActions[number] or {})[2]
elseif topic == "stacks" then
return get_stacks(pos)
elseif topic == "text" then
local meta = minetest.get_meta(pos)
meta:set_string("text", tostring(payload))
meta:set_string("formspec", formspec2(pos))
else
return "unsupported"
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 66 then
local meta = minetest.get_meta(pos)
meta:set_string("text", tostring(payload))
meta:set_string("formspec", formspec2(pos))
return 0
else
return 2
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then -- Chest State
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return 0, {techage.get_inv_state_num(inv, "main")}
elseif topic == 138 and payload[1] == 1 then -- Sensor Chests State (action)
local meta = minetest.get_meta(pos)
local number = meta:get_string("node_number")
local action = (PlayerActions[number] or {})[2] or "None"
return 0, {({put = 1, get = 2})[action] or 0}
elseif topic == 138 and payload[1] == 2 then -- Sensor Chests State (player name)
local meta = minetest.get_meta(pos)
local number = meta:get_string("node_number")
return 0, (PlayerActions[number] or {})[1]
elseif topic == 138 and payload[1] == 3 then -- Sensor Chests State (stack item name)
local name, _ = get_stack(pos, payload[2] or 1)
return 0, name
elseif topic == 138 and payload[1] == 4 then -- Sensor Chests State (stack item count)
local _, count = get_stack(pos, payload[2] or 1)
return 0, {count}
else
return 2, ""
end
end,
})
minetest.register_craft({
type = "shapeless",
output = "techage:ta4_sensor_chest",
recipe = {"techage:chest_ta4", "techage:ta4_wlanchip"}
})
@@ -0,0 +1,325 @@
--[[
Techage
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
server.lua:
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local M = minetest.get_meta
local SERVER_CAPA = 5000
local function formspec(nvm)
local names = table.concat(nvm.names or {}, " ")
return "size[9,4]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"field[0.2,1;9,1;names;Allowed user names (space separated):;"..names.."]" ..
"button_exit[3.5,2.5;2,1;exit;Save]"
end
minetest.register_node("techage:ta4_server", {
description = "TA4 Lua Server",
tiles = {
-- up, down, right, left, back, front
"techage_server_top.png",
"techage_server_top.png",
"techage_server_side.png",
"techage_server_side.png^[transformFX",
"techage_server_back.png",
{
name = "techage_server_front.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1,
},
},
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -3/16, -8/16, -7/16, 3/16, 6/16, 7/16},
},
},
after_place_node = function(pos, placer)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local number = techage.add_node(pos, "techage:ta4_server")
meta:set_string("owner", placer:get_player_name())
meta:set_string("number", number)
meta:set_string("formspec", formspec(nvm))
nvm.size = 0
meta:set_string("infotext", "Server "..number..": ("..nvm.size.."/"..SERVER_CAPA..")")
minetest.get_node_timer(pos):start(20)
end,
on_receive_fields = function(pos, formname, fields, player)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local owner = meta:get_string("owner")
if player:get_player_name() == owner then
if fields.names and fields.names ~= "" then
nvm.names = string.split(fields.names, " ")
meta:set_string("formspec", formspec(nvm))
end
end
end,
on_dig = function(pos, node, puncher, pointed_thing)
if minetest.is_protected(pos, puncher:get_player_name()) then
return
end
techage.del_mem(pos)
minetest.node_dig(pos, node, puncher, pointed_thing)
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
on_timer = function(pos, elasped)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
nvm.size = nvm.size or 0
local number = meta:get_string("number")
meta:set_string("infotext", "Server "..number..": ("..nvm.size.."/"..SERVER_CAPA..")")
return true
end,
paramtype = "light",
sunlight_propagates = true,
use_texture_alpha = techage.CLIP,
paramtype2 = "facedir",
groups = {choppy=1, cracky=1, crumbly=1},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
minetest.register_craft({
output = "techage:ta4_server",
recipe = {
{"default:steel_ingot", "dye:black", "default:steel_ingot"},
{"techage:ta4_ramchip", "default:copper_ingot", "techage:ta4_ramchip"},
{"techage:ta4_ramchip", "techage:ta4_wlanchip", "techage:ta4_ramchip"},
},
})
minetest.register_node("techage:ta4_server2", {
description = "TA4 Lua Rack Server",
tiles = {
-- up, down, right, left, back, front
"techage_server2_top.png",
"techage_server2_top.png",
"techage_server2_side.png",
"techage_server2_side.png^[transformFX",
"techage_server2_back.png",
{
name = "techage_server2_front.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1,
},
},
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, -0.4375, -0.4375, 0.5},
{-0.5, 0.4375, -0.5, -0.4375, 0.5, 0.5},
{0.4375, -0.5, -0.5, 0.5, -0.4375, 0.5},
{0.4375, 0.4375, -0.5, 0.5, 0.5, 0.5},
{-0.5, -0.5, -0.375, -0.4375, 0.5, -0.3125},
{-0.5, -0.5, 0.3125, -0.4375, 0.5, 0.375},
{0.4375, -0.5, 0.3125, 0.5, 0.5, 0.375},
{0.4375, -0.5, -0.375, 0.5, 0.5, -0.3125},
{-0.4375, -0.3125, -0.4375, 0.4375, 0.3125, 0.4375},
{0.4375, -0.0625, -0.4375, 0.5, 0, 0.4375},
{-0.5, -0.0625, -0.4375, -0.4375, 0, 0.4375},
}
},
after_place_node = function(pos, placer)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local number = techage.add_node(pos, "techage:ta4_server2")
meta:set_string("owner", placer:get_player_name())
meta:set_string("number", number)
meta:set_string("formspec", formspec(nvm))
nvm.size = 0
meta:set_string("infotext", "Server "..number..": ("..nvm.size.."/"..SERVER_CAPA..")")
minetest.get_node_timer(pos):start(20)
end,
on_receive_fields = function(pos, formname, fields, player)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local owner = meta:get_string("owner")
if player:get_player_name() == owner then
if fields.names and fields.names ~= "" then
nvm.names = string.split(fields.names, " ")
meta:set_string("formspec", formspec(nvm))
end
end
end,
on_dig = function(pos, node, puncher, pointed_thing)
if minetest.is_protected(pos, puncher:get_player_name()) then
return
end
techage.del_mem(pos)
minetest.node_dig(pos, node, puncher, pointed_thing)
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
on_timer = function(pos, elasped)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
nvm.size = nvm.size or 0
local number = meta:get_string("number")
meta:set_string("infotext", "Server "..number..": ("..nvm.size.."/"..SERVER_CAPA..")")
return true
end,
paramtype = "light",
sunlight_propagates = true,
use_texture_alpha = techage.CLIP,
paramtype2 = "facedir",
groups = {choppy=1, cracky=1, crumbly=1},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
minetest.register_craft({
type = "shapeless",
output = "techage:ta4_server2",
recipe = {"techage:ta4_server"},
})
minetest.register_craft({
type = "shapeless",
output = "techage:ta4_server",
recipe = {"techage:ta4_server2"},
})
local function calc_size(v)
if type(v) == "number" then
return 1
elseif type(v) == "boolean" then
return 1
elseif v == nil then
return 0
elseif type(v) == "string" then
return #v
elseif v.MemSize then
return v.MemSize
else
return nil
end
end
local function get_memory(num, name)
local info = techage.get_node_info(num)
if info and info.pos then
local nvm = techage.get_nvm(info.pos)
nvm.names = nvm.names or {}
for _,n in ipairs(nvm.names) do
if name == n then
nvm.data = nvm.data or {}
return nvm
end
end
end
end
local function write_value(nvm, key, item)
if nvm and nvm.size < SERVER_CAPA then
if nvm.data[key] then
nvm.size = nvm.size - calc_size(nvm.data[key])
end
if type(item) == "table" then
item = safer_lua.datastruct_to_table(item)
end
nvm.size = nvm.size + calc_size(item)
nvm.data[key] = item
return true
end
return false
end
local function read_value(nvm, key)
local item = nvm.data[key]
if type(item) == "table" then
item = safer_lua.table_to_datastruct(item)
end
return item
end
techage.register_node({"techage:ta4_server", "techage:ta4_server2"}, {
on_recv_message = function(pos, src, topic, payload)
return "unsupported"
end,
on_node_load = function(pos)
minetest.get_node_timer(pos):start(20)
end,
})
techage.lua_ctlr.register_function("server_read", {
cmnd = function(self, num, key)
if type(key) == "string" then
local nvm = get_memory(num, self.meta.owner)
if nvm then
return read_value(nvm, key)
end
else
self.error("Invalid server_read parameter")
end
end,
help = " $server_read(num, key)\n"..
" Read a value from the server.\n"..
" 'key' must be a string.\n"..
' example: state = $server_read("123", "state")'
})
techage.lua_ctlr.register_action("server_write", {
cmnd = function(self, num, key, value)
if type(key) == "string" then
local nvm = get_memory(num, self.meta.owner)
if nvm then
return write_value(nvm, key, value)
end
else
self.error("Invalid server_write parameter")
end
end,
help = " $server_write(num, key, value)\n"..
" Store a value on the server under the key 'key'.\n"..
" 'key' must be a string. 'value' can be either a\n"..
" number, string, boolean, nil or data structure.\n"..
" return value: true if successful or false\n"..
' example: res = $server_write("123", "state", state)'
})
@@ -0,0 +1,261 @@
--[[
Techage
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
terminal.lua:
]]--
local HELP = [[#### TA4 Lua Controller Terminal ####
Send commands to your Controller
and output text messages from your
Controller to the Terminal.
Commands can have up to 80 characters.
Local commands:
- clear = clear screen
- help = this message
- pub = switch to public use
- priv = switch to private use
Global commands:
- send <num> on/off = send on/off event
- msg <num> <text> = send a text message
For more help:
https://github.com/joe7575/techage/wiki
]]
local function formspec1()
return "size[6,4]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"field[0.5,1;5,1;number;TA4 Lua Controller number:;]" ..
"button_exit[1.5,2.5;2,1;exit;Save]"
end
local function formspec2(meta)
local output = meta:get_string("output")
output = minetest.formspec_escape(output)
output = output:gsub("\n", ",")
return "size[9,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"style_type[table,field;font=mono]"..
"table[0.1,0.1;8.6,6.6;output;"..output..";200]"..
"field[0.5,7.6;6,1;cmnd;Enter command;]" ..
"field_close_on_enter[cmnd;false]"..
"button[6.7,7.3;2,1;ok;Enter]"
end
local function output(pos, text)
local meta = minetest.get_meta(pos)
text = meta:get_string("output") .. "\n" .. (text or "")
text = text:sub(-500,-1)
meta:set_string("output", text)
meta:set_string("formspec", formspec2(meta))
end
local function command(pos, cmnd, player)
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if cmnd then
cmnd = cmnd:sub(1,80)
if cmnd == "clear" then
meta:set_string("output", "")
meta:set_string("formspec", formspec2(meta))
elseif cmnd == "help" then
local meta = minetest.get_meta(pos)
meta:set_string("output", HELP)
meta:set_string("formspec", formspec2(meta))
elseif cmnd == "pub" and owner == player then
meta:set_int("public", 1)
--output(pos, player..":$ "..cmnd)
output(pos, "> "..cmnd)
output(pos, "Switched to public use!")
elseif cmnd == "priv" and owner == player then
meta:set_int("public", 0)
--output(pos, player..":$ "..cmnd)
output(pos, "> "..cmnd)
output(pos, "Switched to private use!")
elseif meta:get_int("public") == 1 or owner == player then
-- send <num> on/off
local num, topic = cmnd:match('^send%s+([0-9]+)%s+([onff]+)$')
if num and topic then
local own_number = meta:get_string("own_number")
if techage.lua_ctlr.not_protected(owner, num) then
--output(pos, player..":$ send "..num.." "..topic)
output(pos, "> send "..num.." "..topic)
techage.send_single(own_number, num, topic, nil)
return
end
end
-- msg <num> <text>
local num, text = cmnd:match('^msg%s+([0-9]+)%s+(.+)$')
if num and text then
local own_number = meta:get_string("own_number")
if techage.lua_ctlr.not_protected(owner, num) then
--output(pos, player..":$ msg "..num.." "..text)
output(pos, "> msg "..num.." "..text)
techage.send_single(own_number, num, "msg", text)
return
end
end
local number = meta:get_string("number")
local own_number = meta:get_string("own_number")
if techage.lua_ctlr.not_protected(owner, number) then
--output(pos, player..":$ "..cmnd)
output(pos, "> "..cmnd)
techage.send_single(own_number, number, "term", cmnd)
end
end
end
end
minetest.register_node("techage:ta4_terminal", {
description = "TA4 Lua Controller Terminal",
tiles = {
-- up, down, right, left, back, front
'techage_terminal1_top.png',
'techage_terminal1_bottom.png',
'techage_terminal1_side.png',
'techage_terminal1_side.png',
'techage_terminal1_bottom.png',
"techage_terminal1_front.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-12/32, -16/32, -8/32, 12/32, -14/32, 12/32},
{-12/32, -14/32, 12/32, 12/32, 6/32, 14/32},
},
},
selection_box = {
type = "fixed",
fixed = {
{-12/32, -16/32, -8/32, 12/32, -14/32, 12/32},
{-12/32, -14/32, 12/32, 12/32, 6/32, 14/32},
},
},
after_place_node = function(pos, placer)
local number = techage.add_node(pos, minetest.get_node(pos).name)
local meta = minetest.get_meta(pos)
meta:set_string("own_number", number)
meta:set_string("formspec", formspec1())
meta:set_string("owner", placer:get_player_name())
meta:set_string("infotext", "TA4 Lua Controller Terminal "..number..": not connected")
end,
on_receive_fields = function(pos, formname, fields, player)
local meta = minetest.get_meta(pos)
if fields.number and fields.number ~= "" then
local owner = meta:get_string("owner")
if techage.check_numbers(fields.number, owner) then
meta:set_string("number", fields.number)
local own_number = meta:get_string("own_number")
meta:set_string("infotext", "TA4 Lua Controller Terminal "..own_number..": connected with "..fields.number)
meta:set_string("formspec", formspec2(meta))
end
elseif (fields.key_enter == "true" or fields.ok == "Enter") and fields.cmnd ~= "" then
command(pos, fields.cmnd, player:get_player_name())
end
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_craft({
output = "techage:ta4_terminal",
recipe = {
{"", "techage:ta4_display", ""},
{"dye:black", "techage:ta4_wlanchip", "default:copper_ingot"},
{"", "techage:aluminum", ""},
},
})
techage.register_node({"techage:ta4_terminal"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "term" then
output(pos, payload)
return true
elseif topic == "msg" then
output(pos, tostring(payload.src)..": "..tostring(payload.text))
return true
end
end,
})
techage.lua_ctlr.register_function("get_term", {
cmnd = function(self)
return techage.lua_ctlr.get_command(self.meta.number)
end,
help = ' $get_term() --> text string or nil\n'..
' Read an entered string (command) from the Terminal.\n'..
' example: s = $get_term()\n'..
" The Terminal has to be connected to the controller."
})
techage.lua_ctlr.register_action("put_term", {
cmnd = function(self, num, text)
text = tostring(text or "")
if techage.lua_ctlr.not_protected(self.meta.owner, num) then
techage.send_single(self.meta.number, num, "term", text)
end
end,
help = " $put_term(num, text)\n"..
' Send a text line to the terminal with number "num".\n'..
' example: $put_term("0123", "Hello "..name)'
})
techage.lua_ctlr.register_function("get_msg", {
cmnd = function(self, raw)
local msg = techage.lua_ctlr.get_msg(self.meta.number)
if msg then
local data = msg.data
if not raw then
data = tostring(data or "")
end
return msg.src, data
end
end,
help = ' $get_msg([raw]) --> number and any value or nil\n'..
' If the optional `raw` parameter is not set or false,\n'..
' the second return value is guaranteed to be a string.\n'..
' Read a received messages. Number is the node\n'..
' number of the sender.\n'..
' example: num,msg = $get_msg().'
})
techage.lua_ctlr.register_action("send_msg", {
cmnd = function(self, num, data)
if techage.lua_ctlr.not_protected(self.meta.owner, num) then
techage.send_single(self.meta.number, num, "msg", data)
end
end,
help = " $send_msg(num, data)\n"..
' Send a message to the controller with number "num".\n'..
' example: $send_msg("0123", "test")'
})