Difference between revisions of "User:FeXoR"
Jump to navigation
Jump to search
(Number of voxel calculations for diamonds in different orientations) |
|||
(22 intermediate revisions by the same user not shown) | |||
Line 12: | Line 12: | ||
− | Builds | + | = Builds = |
<gallery> | <gallery> | ||
pandorabox_shipbuildingcontest2021_jolly_hedgy.png|Jolly Hedgy | pandorabox_shipbuildingcontest2021_jolly_hedgy.png|Jolly Hedgy | ||
</gallery> | </gallery> | ||
− | Glitchy things | + | = Glitchy things = |
<gallery> | <gallery> | ||
translucent_pod2_bottom_01.png | translucent_pod2_bottom_01.png | ||
translucent_pod2_bottom_02.png | translucent_pod2_bottom_02.png | ||
translucent_pod2_bottom_03.png | translucent_pod2_bottom_03.png | ||
+ | unified_inventory_in_minetest_5_1_1.png | ||
+ | monitor_visible_at_light_level_0.png | ||
</gallery> | </gallery> | ||
+ | |||
+ | = LUA Controller Code = | ||
+ | |||
+ | == Event Catcher - Mooncontroller == | ||
+ | |||
+ | <syntaxhighlight lang="lua"> | ||
+ | -- Event Catcher code for the mooncontroller | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Helper functions | ||
+ | -- ######## | ||
+ | |||
+ | local function get_string(data, maxdepth) | ||
+ | local maxdepth = maxdepth or 3 | ||
+ | if type(data) == "string" then return data | ||
+ | elseif type(data) == "table" and maxdepth > 0 then | ||
+ | local oString = "{" | ||
+ | for k, v in pairs(data) do | ||
+ | local val = v | ||
+ | if type(v) == "table" then val = get_string(val, maxdepth - 1) end | ||
+ | oString = oString .. tostring(k) .. "=" .. tostring(val) .. ", " | ||
+ | end | ||
+ | return string.sub(oString, 1, -3) .. "}" | ||
+ | else | ||
+ | return tostring(data) | ||
+ | end | ||
+ | return "Something went wrong!" | ||
+ | end | ||
+ | |||
+ | local function get_time_string(datetable) | ||
+ | local date_table = datetable or os.datetable() | ||
+ | local date_string = date_table.year .. "-" .. date_table.month .. "-" .. date_table.day | ||
+ | local time_string = date_table.hour .. ":" .. date_table.min .. ":" .. date_table.sec | ||
+ | return date_string .. "T" .. time_string | ||
+ | end | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Event Catcher | ||
+ | -- ######## | ||
+ | |||
+ | if mem.events == nil then mem.events = {count = 0} end | ||
+ | |||
+ | print("#" .. tostring(mem.events.count) .. ", " .. get_time_string() .. ":") | ||
+ | print(get_string(event)) | ||
+ | |||
+ | mem.events.count = (mem.events.count + 1)%1000 | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Variable Printer | ||
+ | -- ######## | ||
+ | |||
+ | help = "\tType 'variables' to get a list of all global variables" | ||
+ | help = help .. "\n\tType the name of a variable to print it e.g. _G or help" | ||
+ | if event.type == "program" then print(help) end | ||
+ | |||
+ | local variables = {} | ||
+ | for k, v in pairs(_G) do | ||
+ | variables[k] = v | ||
+ | end | ||
+ | |||
+ | if event.type == "terminal" then | ||
+ | if event.text == "variables" then | ||
+ | n_vars = 0 | ||
+ | for k, v in pairs(variables) do | ||
+ | n_vars = n_vars + 1 | ||
+ | print(k .. " (" .. type(_G[k]) .. ")") | ||
+ | end | ||
+ | print("\t" .. tostring(n_vars) .. " variables") | ||
+ | else | ||
+ | print(variables[event.text]) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | |||
+ | -- MIT License | ||
+ | -- | ||
+ | -- Copyright (c) 2021 Florian Finke | ||
+ | -- | ||
+ | -- 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. | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Some basic LUA code to log digiline messages and steer a jumpdrive with a touchscreen == | ||
+ | |||
+ | <syntaxhighlight lang="lua"> | ||
+ | --[[ | ||
+ | Basic Pandorabox tools | ||
+ | |||
+ | BUG: | ||
+ | - When a numerical value is contained in event.msg the LUAc run will fail! Resolve by checking for type "table" before probing keys! | ||
+ | - Current coordinates in LUAc doesn't reset when a jump was requested but not executed (e.g. obstructed, Refresh+Reset fixes the state) | ||
+ | TODO: | ||
+ | - Refreshing the touchscreen repaints the formspec fully. Make use of replacing GUI elements! | ||
+ | - Add page for channels and other settings | ||
+ | - Changing the radius does not adjust instant_jump distance (This may result in jump into itself) | ||
+ | - Changing instant_jump distance too small is actually set to the smallest possible but late for the GUI to always show that | ||
+ | - Unify usage of linebuffer | ||
+ | - Hardcoded textarea name "display" (cut in logging to prevent logging itself inflating string size) prevents more than one such textarea per page | ||
+ | ]] | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Optimization | ||
+ | -- ######## | ||
+ | local math, os, string, table = math, os, string, table | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Settings | ||
+ | -- ######## | ||
+ | |||
+ | local permission = {authorised_users = {"singleplayer", "FeXoR", "6r1d", "SX", "SwissalpS", "Huhhila", "BuckarooBanzai", "admin"}} | ||
+ | if mem.permission == nil then mem.permission = {ignore = false} end | ||
+ | permission.check = function(user) | ||
+ | if mem.permission.ignore == true then return true end | ||
+ | local is_allowed = false | ||
+ | for i, u in ipairs(permission.authorised_users) do | ||
+ | if user == u then | ||
+ | is_allowed = true | ||
+ | break | ||
+ | end | ||
+ | end | ||
+ | return is_allowed | ||
+ | end | ||
+ | |||
+ | local event_catcher = {touchscreen = {max_lines = 30}, monitor = {channel = "mon_ec"}} | ||
+ | if mem.events == nil then mem.events = {count = 0} end | ||
+ | |||
+ | local jumpdrive = {channel = "jumpdrive"} | ||
+ | if mem.linebuffer == nil then | ||
+ | mem.linebuffer = {} | ||
+ | if mem.linebuffer.jumpdrive == nil then mem.linebuffer.jumpdrive = {"Here the Jumpdrive's responses will be shown."} end | ||
+ | end | ||
+ | |||
+ | local quarries = {channel = "quarry"} | ||
+ | if mem.reset_quarries_on_jump == nil then mem.reset_quarries_on_jump = false end | ||
+ | |||
+ | local touchscreen = { | ||
+ | channel = "ts", | ||
+ | pages = {"Events", "Jumpdrive", "LUA Libs"}, | ||
+ | update_pages = {"Events"}, | ||
+ | permissions = {"Open", "Users", "Locked"}, | ||
+ | linebuffer = {jumpdrive = {memory = mem.linebuffer.jumpdrive, max_lines = 30}} | ||
+ | } | ||
+ | if mem.page == nil then | ||
+ | mem.page = 1 | ||
+ | table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page]) | ||
+ | end | ||
+ | if mem.ts_lock == nil then mem.ts_lock = 2 end | ||
+ | |||
+ | local breakers = {port = "b"} | ||
+ | |||
+ | if mem.instant_jump == nil then mem.instant_jump = {distance = 50} end | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Helper functions | ||
+ | -- ######## | ||
+ | |||
+ | local character = {} | ||
+ | character.is_numeric = function (sChar) | ||
+ | if sChar:byte() >= 48 and sChar:byte() <= 57 then return true | ||
+ | else return false | ||
+ | end | ||
+ | end | ||
+ | |||
+ | |||
+ | local coordinates = {names = {"x", "y", "z"}} | ||
+ | |||
+ | -- TODO: Probably make more readable by by using character type definition with methods is_numeric and is_minus | ||
+ | function coordinates:to_table(sInput) | ||
+ | local tNumberList = {} | ||
+ | if type(sInput) == "string" then | ||
+ | local bContinuous = false | ||
+ | for nChar = 1, #sInput do | ||
+ | local nByte = sInput:byte(nChar) | ||
+ | -- A new numerical string starts - potentially - ignoring repetitions of "-" | ||
+ | if (bContinuous == false and (nByte == 45 or (nByte >= 48 and nByte <= 57))) or (nByte == 45 and sInput:byte(nChar-1) ~= 45) then | ||
+ | -- Override previous non valid numerical string "-" | ||
+ | if #tNumberList > 0 and tNumberList[#tNumberList] == "-" then tNumberList[#tNumberList] = string.char(nByte) | ||
+ | else table.insert(tNumberList, string.char(nByte)) | ||
+ | end | ||
+ | bContinuous = true | ||
+ | elseif bContinuous and (nByte >= 48 and nByte <= 57) then | ||
+ | tNumberList[#tNumberList] = tostring(tNumberList[#tNumberList]) .. string.char(nByte) | ||
+ | elseif nByte ~= 45 then | ||
+ | bContinuous = false | ||
+ | end | ||
+ | end | ||
+ | -- Remove tailing non valid numerical string "-" | ||
+ | if tNumberList[#tNumberList] == "-" then tNumberList[#tNumberList] = nil end | ||
+ | end | ||
+ | local tOutput = {} | ||
+ | for i, name in ipairs(self.names) do | ||
+ | tOutput[name] = tonumber(tNumberList[i] or "0") | ||
+ | end | ||
+ | return tOutput | ||
+ | end | ||
+ | |||
+ | function coordinates:to_string(coordinate_table) return coordinate_table.x .. "," .. coordinate_table.y .. "," .. coordinate_table.z end | ||
+ | |||
+ | |||
+ | local function get_string(data, maxdepth) | ||
+ | local maxdepth = maxdepth or 3 | ||
+ | if type(data) == "string" then return data | ||
+ | elseif type(data) == "table" and maxdepth > 0 then | ||
+ | local oString = "{" | ||
+ | for k, v in pairs(data) do | ||
+ | local val = v | ||
+ | if type(v) == "table" then val = get_string(val, maxdepth - 1) end | ||
+ | oString = oString .. tostring(k) .. "=" .. tostring(val) .. ", " | ||
+ | end | ||
+ | return string.sub(oString, 1, -3) .. "}" | ||
+ | else | ||
+ | return tostring(data) | ||
+ | end | ||
+ | return "Something went wrong!" | ||
+ | end | ||
+ | |||
+ | local function get_time_string(datetable) | ||
+ | local date_table = datetable or os.datetable() | ||
+ | local date_string = date_table.year .. "-" .. date_table.month .. "-" .. date_table.day | ||
+ | local time_string = date_table.hour .. ":" .. date_table.min .. ":" .. date_table.sec | ||
+ | return date_string .. "T" .. time_string | ||
+ | end | ||
+ | |||
+ | local function merge_shallow_tables(t1, t2) | ||
+ | local t3 = {} | ||
+ | for k, v in pairs(t1) do t3[k] = v end | ||
+ | for k, v in pairs(t2) do t3[k] = v end | ||
+ | return t3 | ||
+ | end | ||
+ | |||
+ | local function add_line_to_buffer(linebuffer, message) | ||
+ | -- expects linebuffer to be an array with keys memory (link to line table in mem) and max_lines (integer) | ||
+ | if type(message) ~= "string" then message = get_string(message) end | ||
+ | table.insert(linebuffer.memory, 1, message) | ||
+ | while table.maxn(linebuffer.memory) > linebuffer.max_lines do table.remove(linebuffer.memory) end | ||
+ | end | ||
+ | |||
+ | local function touchscreen_add_line(msg) | ||
+ | table.insert(mem.event_catcher.touchscreen_line_table, 1, tostring(mem.events.count) .. ": " .. tostring(msg)) | ||
+ | while table.maxn(mem.event_catcher.touchscreen_line_table) > event_catcher.touchscreen.max_lines do | ||
+ | table.remove(mem.event_catcher.touchscreen_line_table) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | local function send_to_monitors(message) | ||
+ | -- Omitt appending it's own and other "display" type content to avoid doubling the output | ||
+ | if message ~= nil and message.msg ~= nil and message.msg.display ~= nil then message.msg.display = "<cut>" end | ||
+ | |||
+ | if message.channel then digiline_send(event_catcher.monitor.channel, message.channel) | ||
+ | elseif message.type then digiline_send(event_catcher.monitor.channel, message.type) | ||
+ | else digiline_send(event_catcher.monitor.channel, get_string(message, 1)) end | ||
+ | if message ~= nil and message.type == "interrupt" then message.time = get_time_string() end | ||
+ | touchscreen_add_line(get_string(message)) | ||
+ | end | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Touchscreen | ||
+ | -- ######## | ||
+ | local function update_page(page) | ||
+ | if touchscreen.pages[mem.page] == page then | ||
+ | local message = { | ||
+ | {command = "clear"}, | ||
+ | -- BUG background9 needs to be before bgcolor | ||
+ | -- {command = "add", element = "background9", X = 0, Y = 0, W = 0, H = 0, image = "ui_formbg_9_sliced.png", auto_clip = true, middle = 16}, | ||
+ | -- BUG focus doesn't seem to work at all: focus = "target" | ||
+ | {command = "set", width = 13, height = 10, no_prepend = true, real_coordinates = true}, | ||
+ | {command = "add", element = "bgcolor", bgcolor = "#202040FF", fullscreen = "false", fbgcolor = "#10101040"}, | ||
+ | |||
+ | {command = "add", element = "label", label = "Page:", X=0.2,Y=0.3}, | ||
+ | {command = "add", element = "textlist", name = "page", listelements = touchscreen.pages, selected_id = mem.page, X=0.1,Y=0.5,W=1.5,H=7.7}, | ||
+ | |||
+ | {command = "add", element = "label", label = "Lock:", X=0.2,Y=8.5}, | ||
+ | {command = "add", element = "textlist", name = "lock", listelements = touchscreen.permissions, selected_id = mem.ts_lock, X=0.1,Y=8.7,W=1.5,H=1.2}, | ||
+ | } | ||
+ | if page == "Events" then | ||
+ | table.insert(message, {command = "add", element = "textarea", name = "display", label = "Events:", | ||
+ | default = table.concat(mem.event_catcher.touchscreen_line_table, "\n"), X=1.5, Y=0.55, W=11.25, H=9.3}) | ||
+ | |||
+ | elseif page == "Jumpdrive" then | ||
+ | table.insert(message, {command = "add", element = "button", name = "request_data", label = "Refresh", X=1.7,Y=0.25,W=1.2,H=0.5}) | ||
+ | table.insert(message, {command = "add", element = "label", X=3.1, Y=0.5, | ||
+ | label = "Distance: " .. tostring(math.ceil(mem.jumpdrive.distance)) .. " | " .. | ||
+ | "EU needed: " .. tostring(math.ceil(mem.jumpdrive.power_req)) .. " stored: " .. tostring(math.ceil(mem.jumpdrive.powerstorage)) | ||
+ | }) | ||
+ | |||
+ | -- BUG The "H" parameter only shifts a field instead of resizing it. Best leave it out (same as H=0.8 | ||
+ | -- BUG The "set" focus propperty doesn't seem to work. The first input field added get's the focus | ||
+ | table.insert(message, {command = "add", element = "field", name = "target", | ||
+ | label = "Target (Current: " .. coordinates:to_string(mem.jumpdrive.position) .. ")", | ||
+ | default = coordinates:to_string(mem.jumpdrive.target), | ||
+ | X=3.8, Y=1.8, W=4.5}) | ||
+ | |||
+ | -- Needs to be behind (in GUI so in front in code) radius selection or that will be blocked by it's invisible label | ||
+ | table.insert(message, {command = "add", element = "textarea", name = "display", label = "The Jumpdrive says:", | ||
+ | default = table.concat(mem.linebuffer.jumpdrive, "\n"), X=1.6, Y=3.8, W=10.7, H=6}) | ||
+ | |||
+ | table.insert(message, {command = "add", element = "label", label = "Radius", X=12,Y=3.7}) | ||
+ | table.insert(message, {command = "add", element = "textlist", name = "radius", | ||
+ | listelements = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"}, | ||
+ | selected_id = tonumber(mem.jumpdrive.radius), X=12.4,Y=3.85,W=0.5,H=6}) | ||
+ | |||
+ | -- Message very long, split here | ||
+ | -- digiline_send(touchscreen.channel, message) | ||
+ | -- message = {} | ||
+ | |||
+ | -- BUG The "H" parameter only shifts a field instead of resizing it. Best leave it out (same as H=0.8 | ||
+ | table.insert(message, {command = "add", element = "field", name = "jump_step_value", label = "Distance", | ||
+ | default = tostring(mem.instant_jump.distance), X=1.7, Y=1.8, W=1.1}) | ||
+ | table.insert(message, {command = "add", element = "button", name = "jump_step_increase", label = "+", X=1.7,Y=1,W=1.1,H=0.5}) | ||
+ | table.insert(message, {command = "add", element = "button", name = "jump_step_decrease", label = "-", X=1.7,Y=2.6,W=1.1,H=0.5}) | ||
+ | -- | ||
+ | table.insert(message, {command = "add", element = "button_exit", name = "xi", label = "E", X=3.8,Y=1,W=1.5,H=0.5}) | ||
+ | table.insert(message, {command = "add", element = "button_exit", name = "xd", label = "W", X=3.8,Y=2.6,W=1.5,H=0.5}) | ||
+ | table.insert(message, {command = "add", element = "button_exit", name = "yi", label = "^", X=5.3,Y=1,W=1.5,H=0.5}) | ||
+ | table.insert(message, {command = "add", element = "button_exit", name = "yd", label = "v", X=5.3,Y=2.6,W=1.5,H=0.5}) | ||
+ | table.insert(message, {command = "add", element = "button_exit", name = "zi", label = "N", X=6.8,Y=1,W=1.5,H=0.5}) | ||
+ | table.insert(message, {command = "add", element = "button_exit", name = "zd", label = "S", X=6.8,Y=2.6,W=1.5,H=0.5}) | ||
+ | |||
+ | table.insert(message, {command = "add", element = "button", name = "reset_target", label = "Reset", X=2.8,Y=1.8,W=1,H=0.8}) | ||
+ | table.insert(message, {command = "add", element = "button", name = "set_target", label = "Set", X=8.3,Y=1.8,W=1,H=0.8}) | ||
+ | table.insert(message, {command = "add", element = "button", name = "simulate", label = "Test", X=9.4,Y=1.8,W=1,H=0.8}) | ||
+ | table.insert(message, {command = "add", element = "button_exit", name = "jump", label = "Jump", X=10.5,Y=1.8,W=1.5,H=0.8}) | ||
+ | |||
+ | table.insert(message, {command = "add", element = "checkbox", name = "reset_quarries_on_jump", label = "Reset quarries on jump", selected = mem.reset_quarries_on_jump, X=8.5,Y=3}) | ||
+ | else | ||
+ | table.insert(message, {command = "add", element = "label", label = "This page is not yet handled: " .. tostring(touchscreen.pages[mem.page]), X=4,Y=4}) | ||
+ | end | ||
+ | |||
+ | digiline_send(touchscreen.channel, message) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | -- Always mark current page for update when "Execute" is clicked to provide a method to update any page on a newly placed touchscreen | ||
+ | if event.type == "program" then table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page]) end | ||
+ | |||
+ | -- Handle touchscreen messages | ||
+ | if event.type == "digiline" and event.channel == touchscreen.channel and event.msg then | ||
+ | if event.msg.page ~= nil then | ||
+ | local i_page = tonumber(string.sub(event.msg.page, 5)) | ||
+ | if i_page ~= mem.page then | ||
+ | mem.page = i_page | ||
+ | table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page]) | ||
+ | end | ||
+ | elseif event.msg.lock ~= nil then | ||
+ | local i_lock = tonumber(string.sub(event.msg.lock, 5)) | ||
+ | if permission.check(event.msg.clicker) then | ||
+ | if i_lock ~= mem.ts_lock then | ||
+ | mem.ts_lock = i_lock | ||
+ | if mem.ts_lock == 1 then | ||
+ | digiline_send(touchscreen.channel, {command = "unlock"}) | ||
+ | mem.permission.ignore = true | ||
+ | elseif mem.ts_lock == 2 then | ||
+ | digiline_send(touchscreen.channel, {command = "unlock"}) | ||
+ | mem.permission.ignore = false | ||
+ | elseif mem.ts_lock == 3 then | ||
+ | digiline_send(touchscreen.channel, {command = "lock"}) | ||
+ | mem.permission.ignore = false | ||
+ | else send_to_monitors("Unhandled ts_lock value: " .. tostring(mem.ts_lock)) | ||
+ | end | ||
+ | table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page]) | ||
+ | end | ||
+ | else | ||
+ | send_to_monitors("You can't unlock, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | elseif touchscreen.pages[mem.page] == "Jumpdrive" then | ||
+ | local authorised = permission.check(event.msg.clicker) | ||
+ | local min_jump_step_value = 2 * mem.jumpdrive.radius + 1 | ||
+ | |||
+ | if event.msg.jump_step_value ~= nil then | ||
+ | if tonumber(event.msg.jump_step_value) < min_jump_step_value then mem.instant_jump.distance = min_jump_step_value | ||
+ | else mem.instant_jump.distance = tonumber(event.msg.jump_step_value) end | ||
+ | if tonumber(event.msg.jump_step_value) ~= mem.instant_jump.distance then table.insert(touchscreen.update_pages, 1, "Jumpdrive") end | ||
+ | end | ||
+ | |||
+ | if event.msg.radius ~= nil then | ||
+ | if authorised then | ||
+ | mem.jumpdrive.radius = tonumber(string.sub(event.msg.radius, 5)) | ||
+ | if event.msg.target ~= nil then | ||
+ | mem.jumpdrive.target = coordinates:to_table(event.msg.target) | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", r = mem.jumpdrive.radius, formupdate = true}, mem.jumpdrive.target)) | ||
+ | else | ||
+ | digiline_send(jumpdrive.channel, {command = "set", r = mem.jumpdrive.radius, formupdate = true}) | ||
+ | end | ||
+ | digiline_send(jumpdrive.channel, {command = "get"}) | ||
+ | else | ||
+ | send_to_monitors("You can't change the radius, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | |||
+ | elseif event.msg.key_enter_field ~= nil then | ||
+ | if event.msg.key_enter_field == "target" then | ||
+ | mem.jumpdrive.target = coordinates:to_table(event.msg.target) | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "get"}) | ||
+ | elseif event.msg.key_enter_field == "jump_step_value" then | ||
+ | table.insert(touchscreen.update_pages, 1, "Jumpdrive") | ||
+ | else send_to_monitors("Unknown key_enter_field: " .. tostring(event.msg.key_enter_field)) end | ||
+ | |||
+ | elseif event.msg.reset_target ~= nil then | ||
+ | digiline_send(jumpdrive.channel, {command = "reset"}) | ||
+ | digiline_send(jumpdrive.channel, {command = "get"}) | ||
+ | elseif event.msg.set_target ~= nil then | ||
+ | if event.msg.target ~= nil then | ||
+ | mem.jumpdrive.target = coordinates:to_table(event.msg.target) | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "get"}) | ||
+ | end | ||
+ | elseif event.msg.request_data ~= nil then | ||
+ | mem.jumpdrive.target = coordinates:to_table(event.msg.target) | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "get"}) | ||
+ | elseif event.msg.simulate ~= nil then | ||
+ | mem.jumpdrive.target = coordinates:to_table(event.msg.target) | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "simulate"}) | ||
+ | elseif event.msg.jump ~= nil then | ||
+ | if authorised then | ||
+ | mem.jumpdrive.target = coordinates:to_table(event.msg.target) | ||
+ | -- mem.jumpdrive.target = mem.jumpdrive.position | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "jump"}) | ||
+ | else | ||
+ | send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | |||
+ | elseif event.msg.jump_step_increase ~= nil then | ||
+ | local target_jump_step_value = tonumber(event.msg.jump_step_value) + 1 | ||
+ | if target_jump_step_value > min_jump_step_value then mem.instant_jump.distance = target_jump_step_value | ||
+ | else mem.instant_jump.distance = min_jump_step_value end | ||
+ | if mem.instant_jump.distance ~= tonumber(event.msg.jump_step_value) then table.insert(touchscreen.update_pages, 1, "Jumpdrive") end | ||
+ | elseif event.msg.jump_step_decrease ~= nil then | ||
+ | local target_jump_step_value = tonumber(event.msg.jump_step_value) - 1 | ||
+ | if target_jump_step_value > min_jump_step_value then mem.instant_jump.distance = target_jump_step_value | ||
+ | else mem.instant_jump.distance = min_jump_step_value end | ||
+ | if mem.instant_jump.distance ~= tonumber(event.msg.jump_step_value) then table.insert(touchscreen.update_pages, 1, "Jumpdrive") end | ||
+ | elseif event.msg.xi ~= nil then | ||
+ | if authorised then | ||
+ | -- mem.jumpdrive.target = mem.jumpdrive.position | ||
+ | mem.jumpdrive.target.x = mem.jumpdrive.position.x + mem.instant_jump.distance | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "jump"}) | ||
+ | else | ||
+ | send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | elseif event.msg.xd ~= nil then | ||
+ | if authorised then | ||
+ | -- mem.jumpdrive.target = mem.jumpdrive.position | ||
+ | mem.jumpdrive.target.x = mem.jumpdrive.position.x - mem.instant_jump.distance | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "jump"}) | ||
+ | else | ||
+ | send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | elseif event.msg.yi ~= nil then | ||
+ | if authorised then | ||
+ | -- mem.jumpdrive.target = mem.jumpdrive.position | ||
+ | mem.jumpdrive.target.y = mem.jumpdrive.position.y + mem.instant_jump.distance | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "jump"}) | ||
+ | else | ||
+ | send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | elseif event.msg.yd ~= nil then | ||
+ | if authorised then | ||
+ | -- mem.jumpdrive.target = mem.jumpdrive.position | ||
+ | mem.jumpdrive.target.y = mem.jumpdrive.position.y - mem.instant_jump.distance | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "jump"}) | ||
+ | else | ||
+ | send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | elseif event.msg.zi ~= nil then | ||
+ | if authorised then | ||
+ | -- mem.jumpdrive.target = mem.jumpdrive.position | ||
+ | mem.jumpdrive.target.z = mem.jumpdrive.position.z + mem.instant_jump.distance | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "jump"}) | ||
+ | else | ||
+ | send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | elseif event.msg.zd ~= nil then | ||
+ | if authorised then | ||
+ | -- mem.jumpdrive.target = mem.jumpdrive.position | ||
+ | mem.jumpdrive.target.z = mem.jumpdrive.position.z - mem.instant_jump.distance | ||
+ | digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target)) | ||
+ | digiline_send(jumpdrive.channel, {command = "jump"}) | ||
+ | else | ||
+ | send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | elseif event.msg.reset_quarries_on_jump ~= nil then | ||
+ | if authorised then | ||
+ | -- mem.reset_quarries_on_jump = event.msg.reset_quarries_on_jump | ||
+ | if event.msg.reset_quarries_on_jump == "true" then mem.reset_quarries_on_jump = true | ||
+ | else mem.reset_quarries_on_jump = false | ||
+ | end | ||
+ | table.insert(touchscreen.update_pages, 1, "Jumpdrive") | ||
+ | else | ||
+ | send_to_monitors("You can't change this, " .. tostring(event.msg.clicker) .. " ;)") | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Jumpdrive | ||
+ | -- ######## | ||
+ | if mem.jumpdrive == nil then | ||
+ | mem.jumpdrive = {radius = 1, power_req = 0, distance = 0, powerstorage = 0, position = {x=0,y=0,z=0}, target = {x=0,y=0,z=0}, success = false, msg = "", time = 0} | ||
+ | end | ||
+ | if event.type == "program" then digiline_send(jumpdrive.channel, {command = "get"}) end | ||
+ | |||
+ | if event.type == "digiline" and event.channel == jumpdrive.channel and event.msg then | ||
+ | local output = "" | ||
+ | local updated = {} | ||
+ | for k, v in pairs(event.msg) do | ||
+ | if mem.jumpdrive[k] ~= nil then | ||
+ | -- if mem.jumpdrive[k] ~= v then output = output .. " " .. tostring(k) .. ": " .. get_string(mem.jumpdrive[k]) .. " -> " .. get_string(v) end | ||
+ | mem.jumpdrive[k] = v | ||
+ | else | ||
+ | add_line_to_buffer(touchscreen.linebuffer.jumpdrive, "Unknown jumpdrive propperty: " .. get_string(k) .. ":" .. get_string(v)) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | if event.msg.success ~= nil then | ||
+ | if event.msg.success == true then | ||
+ | output = output .. " Success!" | ||
+ | if mem.reset_quarries_on_jump then digiline_send(quarries.channel, {command = "set", restart = true}) end | ||
+ | else output = output .. " Failure! (Best refresh and reset)" | ||
+ | end | ||
+ | end | ||
+ | if event.msg.msg then output = output .. " " .. event.msg.msg end | ||
+ | if event.msg.time then | ||
+ | output = output .. " Jumped (" .. tostring(event.msg.time) .. ")" | ||
+ | mem.jumpdrive.position = mem.jumpdrive.target | ||
+ | digiline_send(jumpdrive.channel, {command = "get"}) | ||
+ | end | ||
+ | if output ~= nil then | ||
+ | if output ~= "" then add_line_to_buffer(touchscreen.linebuffer.jumpdrive, tostring(mem.events.count) .. ":" .. output) end | ||
+ | else | ||
+ | add_line_to_buffer(touchscreen.linebuffer.jumpdrive, tostring(mem.events.count) .. ":" .. "Output was nil!") | ||
+ | end | ||
+ | |||
+ | table.insert(touchscreen.update_pages, 1, "Jumpdrive") | ||
+ | end | ||
+ | |||
+ | |||
+ | -- ######## | ||
+ | -- Event Catcher and update screens | ||
+ | -- ######## | ||
+ | if mem.event_catcher == nil then | ||
+ | mem.event_catcher = {touchscreen_line_table = {"Initialized at " .. get_time_string() .. ", " .. _VERSION}} | ||
+ | end | ||
+ | |||
+ | send_to_monitors(event) | ||
+ | |||
+ | for i, page in ipairs(touchscreen.update_pages) do | ||
+ | if page == touchscreen.pages[mem.page] then | ||
+ | update_page(touchscreen.pages[mem.page]) | ||
+ | break | ||
+ | end | ||
+ | end | ||
+ | |||
+ | mem.events.count = mem.events.count + 1 | ||
+ | |||
+ | |||
+ | --[[ | ||
+ | MIT License | ||
+ | Copyright (c) 2021 Florian Finke | ||
+ | |||
+ | 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. | ||
+ | ]] | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Game Controller steered Jumpdrive with Noteblock feedback == | ||
+ | |||
+ | <syntaxhighlight lang="lua"> | ||
+ | --[[ | ||
+ | Usage: | ||
+ | - Mount the game controller (Rightclick it) | ||
+ | - Set direction of travel (Look that way) | ||
+ | - Increase jump distance (Hold the jump key and slightly move your mouse [or pushing the forward key]) | ||
+ | - Jump (Release the jump button) | ||
+ | Setup: | ||
+ | LUAc with this code attached to: | ||
+ | - Jumpdrive (jumpdrive:engine), digiline channel "jumpdrive" (default) | ||
+ | - Digilines Game Controller (digistuff:controller), digiline channel "gc" | ||
+ | Optional (for feedback): | ||
+ | - Digilines Noteblock (digistuff:noteblock), digiline channel "speaker" | ||
+ | |||
+ | (See the settings to e.g. change the channels) | ||
+ | |||
+ | Jump on ;) | ||
+ | ]] | ||
+ | |||
+ | -- Settings | ||
+ | local users = {"singleplayer", "FeXoR", "6r1d", "SX", "SwissalpS", "Huhhila", "BuckarooBanzai", "admin"} | ||
+ | local jumpdrive_channel = "jumpdrive" | ||
+ | local game_controller_channel = "gc" | ||
+ | local note_block_channel = "speaker" | ||
+ | local delay = heat | ||
+ | local sounds = {"c", "d", "e", "f", "g", "a", "b", "c2"} | ||
+ | --local sounds = {"c", "csharp", "d", "dsharp", "e", "f", "fsharp", "g", "gsharp", "a", "asharp", "b", "c2", "csharp2", "d2", "dsharp2", "e2", "f2", "fsharp2", "g2", "gsharp2", "a2", "asharp2", "b2"} | ||
+ | local max_dist = 48 | ||
+ | |||
+ | -- Functions | ||
+ | local function permission_check(user) | ||
+ | for i, u in ipairs(users) do | ||
+ | if user == u then | ||
+ | return true | ||
+ | end | ||
+ | end | ||
+ | return false | ||
+ | end | ||
+ | |||
+ | -- Do stuff | ||
+ | if event.type == "program" then | ||
+ | digiline_send(jumpdrive_channel, {command = "get"}) | ||
+ | digiline_send(note_block_channel, "get_sounds") -- DEBUG | ||
+ | digiline_send(note_block_channel, "digistuff_piezo_short") | ||
+ | --digiline_send(note_block_channel, "default_place_node_metal") | ||
+ | --digiline_send(note_block_channel, "anvil_clang") | ||
+ | --digiline_send(note_block_channel, "sine") | ||
+ | --digiline_send(note_block_channel, "unified_inventory_refill") | ||
+ | --digiline_send(note_block_channel, "homedecor_toilet") | ||
+ | end | ||
+ | |||
+ | if event.channel == jumpdrive_channel and | ||
+ | type(event.msg) == "table" | ||
+ | then | ||
+ | if type(event.msg.position) == "table" then mem.position = event.msg.position end | ||
+ | -- Set jump distance slightly larger than diagonal extend of jumped area even for radius 1 | ||
+ | if type(event.msg.radius) == "number" then mem.min_dist = math.min(4 * event.msg.radius + 2, max_dist) end | ||
+ | if event.msg.success == true then digiline_send(note_block_channel, "technic_laser_mk1") end | ||
+ | if event.msg.success == false then digiline_send(note_block_channel, "technic_laser_mk2") end | ||
+ | end | ||
+ | |||
+ | if event.channel == game_controller_channel then | ||
+ | if event.msg == "player_left" and mem.target == nil then -- Not released pre-jump | ||
+ | mem.power = 0 | ||
+ | digiline_send(note_block_channel, "unified_inventory_refill") | ||
+ | elseif | ||
+ | type(event.msg) == "table" | ||
+ | then | ||
+ | if type(event.msg.name) == "string" and permission_check(event.msg.name) == true then | ||
+ | if event.msg.jump == true then | ||
+ | if type(mem.power) == "number" then | ||
+ | mem.power = math.min(mem.power + 1, #sounds) | ||
+ | else | ||
+ | mem.power = 1 | ||
+ | end | ||
+ | digiline_send(note_block_channel, sounds[mem.power]) | ||
+ | else | ||
+ | if type(mem.power) == "number" and mem.power > 0 | ||
+ | then | ||
+ | if type(event.msg.look_vector) == "table" and | ||
+ | type(mem.position) == "table" and type(mem.min_dist) == "number" | ||
+ | then | ||
+ | local distance = mem.min_dist + (max_dist - mem.min_dist) / #sounds * mem.power | ||
+ | mem.target = { | ||
+ | x = math.floor(0.5 + mem.position.x + distance * event.msg.look_vector.x), | ||
+ | y = math.floor(0.5 + mem.position.y + distance * event.msg.look_vector.y), | ||
+ | z = math.floor(0.5 + mem.position.z + distance * event.msg.look_vector.z) | ||
+ | } | ||
+ | digiline_send(game_controller_channel, "release") | ||
+ | interrupt(delay) | ||
+ | else | ||
+ | digiline_send("DEBUG", "Insufficient information to set target!") | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | else | ||
+ | digiline_send(note_block_channel, "sine") -- Access denied | ||
+ | digiline_send(game_controller_channel, "release") | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | if event.type == "interrupt" then | ||
+ | if mem.position == nil then | ||
+ | digiline_send(jumpdrive_channel, {command = "get"}) | ||
+ | interrupt(delay) | ||
+ | end | ||
+ | if mem.target ~= nil then | ||
+ | digiline_send(jumpdrive_channel, {command = "set", x = mem.target.x, y = mem.target.y, z = mem.target.z}) | ||
+ | mem.target = nil | ||
+ | mem.power = 0 | ||
+ | mem.position = nil | ||
+ | digiline_send(jumpdrive_channel, {command = "jump"}) | ||
+ | interrupt(delay) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | --[[ | ||
+ | MIT License | ||
+ | Copyright (c) 2021 Florian Finke | ||
+ | |||
+ | 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. | ||
+ | ]] | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Some calculation about a diamond in 2 orientations for Hedgehog ;) == | ||
+ | |||
+ | <syntaxhighlight lang="python"> | ||
+ | debug = 0 | ||
+ | |||
+ | print("3D Diamond with square layers (less symmetric)") | ||
+ | # Scatch of layer with width 3: | ||
+ | # ooo | ||
+ | # ooo | ||
+ | # ooo | ||
+ | |||
+ | n = 0 | ||
+ | for i in range(100): | ||
+ | w = 2*i+1 | ||
+ | if debug: print(" Width of layer: " + str(w)) | ||
+ | a = w**2 | ||
+ | if debug: print(" Nodes for this layer: " + str(a)) | ||
+ | n += a | ||
+ | |||
+ | n *= 2 | ||
+ | w = 2*100+1 | ||
+ | if debug: print(" Central width: "+str(w)) | ||
+ | |||
+ | a = w**2 | ||
+ | if debug: print(" Nodes for center layer: " + str(a)) | ||
+ | |||
+ | n += a | ||
+ | print(" Total number of nodes: " + str(n)) | ||
+ | # 2707001 | ||
+ | |||
+ | # (2*100+1)**2 + 2 * ((2*0+1)**2 + (2*1+1)**2 + ... + (2*99+1)**2) | ||
+ | # = (2*100+1)**2 + 2 * sum(i=0 to 99)[(2*i+1)**2] | ||
+ | # = (2*100+1)**2 + 2/3*(99+1)*(2*99+1)*(2*99+3) | ||
+ | print(" (Test: " + str((2*100+1)**2 + 2/3*(99+1)*(2*99+1)*(2*99+3)) + " )\n") | ||
+ | |||
+ | |||
+ | print("3D Diamond with non-square layers (more symmetric)") | ||
+ | # Scatch of layer with width 3: | ||
+ | # o | ||
+ | # ooo | ||
+ | # o | ||
+ | |||
+ | n = 0 | ||
+ | for i in range(100): | ||
+ | if debug: print(" Width of layer: " + str(2*i+1)) | ||
+ | a = (i+1)*(i+2)-1 | ||
+ | if debug: print(" Nodes for this layer: " + str(a)) | ||
+ | n += a | ||
+ | |||
+ | n *= 2 | ||
+ | if debug: print(" Central width: "+str(2*100+1)) | ||
+ | |||
+ | a = (100+1)*(100+2)-1 | ||
+ | if debug: print(" Nodes for center layer: " + str(a)) | ||
+ | |||
+ | n += a | ||
+ | print(" Total number of nodes: " + str(n)) | ||
+ | # 696901 | ||
+ | |||
+ | # 2 * ((0+1)*(0+2)-1 + (1+1)*(1+2)-1 + ... + (n+1)*(n+2)-1) + (100+1)*(100+2)-1 | ||
+ | # = (100+1)*(100+2)-1 + 2* sum(i=0 to 99)[(i+1)*(i+2)-1] | ||
+ | # = (100+1)*(100+2)-1 + 2/3*(99+1)*(99**2+5*99+3) | ||
+ | print(" (Test: " + str((100+1)*(100+2)-1 + 2/3*(99+1)*(99**2+5*99+3)) + " )\n") | ||
+ | </syntaxhighlight> |
Latest revision as of 15:41, 27 October 2024
Hiho Pandorabox o/
I love this place for the large variety of functional modifications like technic, mesecon, pipeworks, digiline and modifications extending those.
I also value the transparency of this server due to this wiki and its contents like the mod list.
The maintenance you pull off is awesome!
Thank you for this great place ;)
Builds
Glitchy things
LUA Controller Code
Event Catcher - Mooncontroller
-- Event Catcher code for the mooncontroller
-- ########
-- Helper functions
-- ########
local function get_string(data, maxdepth)
local maxdepth = maxdepth or 3
if type(data) == "string" then return data
elseif type(data) == "table" and maxdepth > 0 then
local oString = "{"
for k, v in pairs(data) do
local val = v
if type(v) == "table" then val = get_string(val, maxdepth - 1) end
oString = oString .. tostring(k) .. "=" .. tostring(val) .. ", "
end
return string.sub(oString, 1, -3) .. "}"
else
return tostring(data)
end
return "Something went wrong!"
end
local function get_time_string(datetable)
local date_table = datetable or os.datetable()
local date_string = date_table.year .. "-" .. date_table.month .. "-" .. date_table.day
local time_string = date_table.hour .. ":" .. date_table.min .. ":" .. date_table.sec
return date_string .. "T" .. time_string
end
-- ########
-- Event Catcher
-- ########
if mem.events == nil then mem.events = {count = 0} end
print("#" .. tostring(mem.events.count) .. ", " .. get_time_string() .. ":")
print(get_string(event))
mem.events.count = (mem.events.count + 1)%1000
-- ########
-- Variable Printer
-- ########
help = "\tType 'variables' to get a list of all global variables"
help = help .. "\n\tType the name of a variable to print it e.g. _G or help"
if event.type == "program" then print(help) end
local variables = {}
for k, v in pairs(_G) do
variables[k] = v
end
if event.type == "terminal" then
if event.text == "variables" then
n_vars = 0
for k, v in pairs(variables) do
n_vars = n_vars + 1
print(k .. " (" .. type(_G[k]) .. ")")
end
print("\t" .. tostring(n_vars) .. " variables")
else
print(variables[event.text])
end
end
-- MIT License
--
-- Copyright (c) 2021 Florian Finke
--
-- 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.
Some basic LUA code to log digiline messages and steer a jumpdrive with a touchscreen
--[[
Basic Pandorabox tools
BUG:
- When a numerical value is contained in event.msg the LUAc run will fail! Resolve by checking for type "table" before probing keys!
- Current coordinates in LUAc doesn't reset when a jump was requested but not executed (e.g. obstructed, Refresh+Reset fixes the state)
TODO:
- Refreshing the touchscreen repaints the formspec fully. Make use of replacing GUI elements!
- Add page for channels and other settings
- Changing the radius does not adjust instant_jump distance (This may result in jump into itself)
- Changing instant_jump distance too small is actually set to the smallest possible but late for the GUI to always show that
- Unify usage of linebuffer
- Hardcoded textarea name "display" (cut in logging to prevent logging itself inflating string size) prevents more than one such textarea per page
]]
-- ########
-- Optimization
-- ########
local math, os, string, table = math, os, string, table
-- ########
-- Settings
-- ########
local permission = {authorised_users = {"singleplayer", "FeXoR", "6r1d", "SX", "SwissalpS", "Huhhila", "BuckarooBanzai", "admin"}}
if mem.permission == nil then mem.permission = {ignore = false} end
permission.check = function(user)
if mem.permission.ignore == true then return true end
local is_allowed = false
for i, u in ipairs(permission.authorised_users) do
if user == u then
is_allowed = true
break
end
end
return is_allowed
end
local event_catcher = {touchscreen = {max_lines = 30}, monitor = {channel = "mon_ec"}}
if mem.events == nil then mem.events = {count = 0} end
local jumpdrive = {channel = "jumpdrive"}
if mem.linebuffer == nil then
mem.linebuffer = {}
if mem.linebuffer.jumpdrive == nil then mem.linebuffer.jumpdrive = {"Here the Jumpdrive's responses will be shown."} end
end
local quarries = {channel = "quarry"}
if mem.reset_quarries_on_jump == nil then mem.reset_quarries_on_jump = false end
local touchscreen = {
channel = "ts",
pages = {"Events", "Jumpdrive", "LUA Libs"},
update_pages = {"Events"},
permissions = {"Open", "Users", "Locked"},
linebuffer = {jumpdrive = {memory = mem.linebuffer.jumpdrive, max_lines = 30}}
}
if mem.page == nil then
mem.page = 1
table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page])
end
if mem.ts_lock == nil then mem.ts_lock = 2 end
local breakers = {port = "b"}
if mem.instant_jump == nil then mem.instant_jump = {distance = 50} end
-- ########
-- Helper functions
-- ########
local character = {}
character.is_numeric = function (sChar)
if sChar:byte() >= 48 and sChar:byte() <= 57 then return true
else return false
end
end
local coordinates = {names = {"x", "y", "z"}}
-- TODO: Probably make more readable by by using character type definition with methods is_numeric and is_minus
function coordinates:to_table(sInput)
local tNumberList = {}
if type(sInput) == "string" then
local bContinuous = false
for nChar = 1, #sInput do
local nByte = sInput:byte(nChar)
-- A new numerical string starts - potentially - ignoring repetitions of "-"
if (bContinuous == false and (nByte == 45 or (nByte >= 48 and nByte <= 57))) or (nByte == 45 and sInput:byte(nChar-1) ~= 45) then
-- Override previous non valid numerical string "-"
if #tNumberList > 0 and tNumberList[#tNumberList] == "-" then tNumberList[#tNumberList] = string.char(nByte)
else table.insert(tNumberList, string.char(nByte))
end
bContinuous = true
elseif bContinuous and (nByte >= 48 and nByte <= 57) then
tNumberList[#tNumberList] = tostring(tNumberList[#tNumberList]) .. string.char(nByte)
elseif nByte ~= 45 then
bContinuous = false
end
end
-- Remove tailing non valid numerical string "-"
if tNumberList[#tNumberList] == "-" then tNumberList[#tNumberList] = nil end
end
local tOutput = {}
for i, name in ipairs(self.names) do
tOutput[name] = tonumber(tNumberList[i] or "0")
end
return tOutput
end
function coordinates:to_string(coordinate_table) return coordinate_table.x .. "," .. coordinate_table.y .. "," .. coordinate_table.z end
local function get_string(data, maxdepth)
local maxdepth = maxdepth or 3
if type(data) == "string" then return data
elseif type(data) == "table" and maxdepth > 0 then
local oString = "{"
for k, v in pairs(data) do
local val = v
if type(v) == "table" then val = get_string(val, maxdepth - 1) end
oString = oString .. tostring(k) .. "=" .. tostring(val) .. ", "
end
return string.sub(oString, 1, -3) .. "}"
else
return tostring(data)
end
return "Something went wrong!"
end
local function get_time_string(datetable)
local date_table = datetable or os.datetable()
local date_string = date_table.year .. "-" .. date_table.month .. "-" .. date_table.day
local time_string = date_table.hour .. ":" .. date_table.min .. ":" .. date_table.sec
return date_string .. "T" .. time_string
end
local function merge_shallow_tables(t1, t2)
local t3 = {}
for k, v in pairs(t1) do t3[k] = v end
for k, v in pairs(t2) do t3[k] = v end
return t3
end
local function add_line_to_buffer(linebuffer, message)
-- expects linebuffer to be an array with keys memory (link to line table in mem) and max_lines (integer)
if type(message) ~= "string" then message = get_string(message) end
table.insert(linebuffer.memory, 1, message)
while table.maxn(linebuffer.memory) > linebuffer.max_lines do table.remove(linebuffer.memory) end
end
local function touchscreen_add_line(msg)
table.insert(mem.event_catcher.touchscreen_line_table, 1, tostring(mem.events.count) .. ": " .. tostring(msg))
while table.maxn(mem.event_catcher.touchscreen_line_table) > event_catcher.touchscreen.max_lines do
table.remove(mem.event_catcher.touchscreen_line_table)
end
end
local function send_to_monitors(message)
-- Omitt appending it's own and other "display" type content to avoid doubling the output
if message ~= nil and message.msg ~= nil and message.msg.display ~= nil then message.msg.display = "<cut>" end
if message.channel then digiline_send(event_catcher.monitor.channel, message.channel)
elseif message.type then digiline_send(event_catcher.monitor.channel, message.type)
else digiline_send(event_catcher.monitor.channel, get_string(message, 1)) end
if message ~= nil and message.type == "interrupt" then message.time = get_time_string() end
touchscreen_add_line(get_string(message))
end
-- ########
-- Touchscreen
-- ########
local function update_page(page)
if touchscreen.pages[mem.page] == page then
local message = {
{command = "clear"},
-- BUG background9 needs to be before bgcolor
-- {command = "add", element = "background9", X = 0, Y = 0, W = 0, H = 0, image = "ui_formbg_9_sliced.png", auto_clip = true, middle = 16},
-- BUG focus doesn't seem to work at all: focus = "target"
{command = "set", width = 13, height = 10, no_prepend = true, real_coordinates = true},
{command = "add", element = "bgcolor", bgcolor = "#202040FF", fullscreen = "false", fbgcolor = "#10101040"},
{command = "add", element = "label", label = "Page:", X=0.2,Y=0.3},
{command = "add", element = "textlist", name = "page", listelements = touchscreen.pages, selected_id = mem.page, X=0.1,Y=0.5,W=1.5,H=7.7},
{command = "add", element = "label", label = "Lock:", X=0.2,Y=8.5},
{command = "add", element = "textlist", name = "lock", listelements = touchscreen.permissions, selected_id = mem.ts_lock, X=0.1,Y=8.7,W=1.5,H=1.2},
}
if page == "Events" then
table.insert(message, {command = "add", element = "textarea", name = "display", label = "Events:",
default = table.concat(mem.event_catcher.touchscreen_line_table, "\n"), X=1.5, Y=0.55, W=11.25, H=9.3})
elseif page == "Jumpdrive" then
table.insert(message, {command = "add", element = "button", name = "request_data", label = "Refresh", X=1.7,Y=0.25,W=1.2,H=0.5})
table.insert(message, {command = "add", element = "label", X=3.1, Y=0.5,
label = "Distance: " .. tostring(math.ceil(mem.jumpdrive.distance)) .. " | " ..
"EU needed: " .. tostring(math.ceil(mem.jumpdrive.power_req)) .. " stored: " .. tostring(math.ceil(mem.jumpdrive.powerstorage))
})
-- BUG The "H" parameter only shifts a field instead of resizing it. Best leave it out (same as H=0.8
-- BUG The "set" focus propperty doesn't seem to work. The first input field added get's the focus
table.insert(message, {command = "add", element = "field", name = "target",
label = "Target (Current: " .. coordinates:to_string(mem.jumpdrive.position) .. ")",
default = coordinates:to_string(mem.jumpdrive.target),
X=3.8, Y=1.8, W=4.5})
-- Needs to be behind (in GUI so in front in code) radius selection or that will be blocked by it's invisible label
table.insert(message, {command = "add", element = "textarea", name = "display", label = "The Jumpdrive says:",
default = table.concat(mem.linebuffer.jumpdrive, "\n"), X=1.6, Y=3.8, W=10.7, H=6})
table.insert(message, {command = "add", element = "label", label = "Radius", X=12,Y=3.7})
table.insert(message, {command = "add", element = "textlist", name = "radius",
listelements = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"},
selected_id = tonumber(mem.jumpdrive.radius), X=12.4,Y=3.85,W=0.5,H=6})
-- Message very long, split here
-- digiline_send(touchscreen.channel, message)
-- message = {}
-- BUG The "H" parameter only shifts a field instead of resizing it. Best leave it out (same as H=0.8
table.insert(message, {command = "add", element = "field", name = "jump_step_value", label = "Distance",
default = tostring(mem.instant_jump.distance), X=1.7, Y=1.8, W=1.1})
table.insert(message, {command = "add", element = "button", name = "jump_step_increase", label = "+", X=1.7,Y=1,W=1.1,H=0.5})
table.insert(message, {command = "add", element = "button", name = "jump_step_decrease", label = "-", X=1.7,Y=2.6,W=1.1,H=0.5})
--
table.insert(message, {command = "add", element = "button_exit", name = "xi", label = "E", X=3.8,Y=1,W=1.5,H=0.5})
table.insert(message, {command = "add", element = "button_exit", name = "xd", label = "W", X=3.8,Y=2.6,W=1.5,H=0.5})
table.insert(message, {command = "add", element = "button_exit", name = "yi", label = "^", X=5.3,Y=1,W=1.5,H=0.5})
table.insert(message, {command = "add", element = "button_exit", name = "yd", label = "v", X=5.3,Y=2.6,W=1.5,H=0.5})
table.insert(message, {command = "add", element = "button_exit", name = "zi", label = "N", X=6.8,Y=1,W=1.5,H=0.5})
table.insert(message, {command = "add", element = "button_exit", name = "zd", label = "S", X=6.8,Y=2.6,W=1.5,H=0.5})
table.insert(message, {command = "add", element = "button", name = "reset_target", label = "Reset", X=2.8,Y=1.8,W=1,H=0.8})
table.insert(message, {command = "add", element = "button", name = "set_target", label = "Set", X=8.3,Y=1.8,W=1,H=0.8})
table.insert(message, {command = "add", element = "button", name = "simulate", label = "Test", X=9.4,Y=1.8,W=1,H=0.8})
table.insert(message, {command = "add", element = "button_exit", name = "jump", label = "Jump", X=10.5,Y=1.8,W=1.5,H=0.8})
table.insert(message, {command = "add", element = "checkbox", name = "reset_quarries_on_jump", label = "Reset quarries on jump", selected = mem.reset_quarries_on_jump, X=8.5,Y=3})
else
table.insert(message, {command = "add", element = "label", label = "This page is not yet handled: " .. tostring(touchscreen.pages[mem.page]), X=4,Y=4})
end
digiline_send(touchscreen.channel, message)
end
end
-- Always mark current page for update when "Execute" is clicked to provide a method to update any page on a newly placed touchscreen
if event.type == "program" then table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page]) end
-- Handle touchscreen messages
if event.type == "digiline" and event.channel == touchscreen.channel and event.msg then
if event.msg.page ~= nil then
local i_page = tonumber(string.sub(event.msg.page, 5))
if i_page ~= mem.page then
mem.page = i_page
table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page])
end
elseif event.msg.lock ~= nil then
local i_lock = tonumber(string.sub(event.msg.lock, 5))
if permission.check(event.msg.clicker) then
if i_lock ~= mem.ts_lock then
mem.ts_lock = i_lock
if mem.ts_lock == 1 then
digiline_send(touchscreen.channel, {command = "unlock"})
mem.permission.ignore = true
elseif mem.ts_lock == 2 then
digiline_send(touchscreen.channel, {command = "unlock"})
mem.permission.ignore = false
elseif mem.ts_lock == 3 then
digiline_send(touchscreen.channel, {command = "lock"})
mem.permission.ignore = false
else send_to_monitors("Unhandled ts_lock value: " .. tostring(mem.ts_lock))
end
table.insert(touchscreen.update_pages, 1, touchscreen.pages[mem.page])
end
else
send_to_monitors("You can't unlock, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif touchscreen.pages[mem.page] == "Jumpdrive" then
local authorised = permission.check(event.msg.clicker)
local min_jump_step_value = 2 * mem.jumpdrive.radius + 1
if event.msg.jump_step_value ~= nil then
if tonumber(event.msg.jump_step_value) < min_jump_step_value then mem.instant_jump.distance = min_jump_step_value
else mem.instant_jump.distance = tonumber(event.msg.jump_step_value) end
if tonumber(event.msg.jump_step_value) ~= mem.instant_jump.distance then table.insert(touchscreen.update_pages, 1, "Jumpdrive") end
end
if event.msg.radius ~= nil then
if authorised then
mem.jumpdrive.radius = tonumber(string.sub(event.msg.radius, 5))
if event.msg.target ~= nil then
mem.jumpdrive.target = coordinates:to_table(event.msg.target)
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", r = mem.jumpdrive.radius, formupdate = true}, mem.jumpdrive.target))
else
digiline_send(jumpdrive.channel, {command = "set", r = mem.jumpdrive.radius, formupdate = true})
end
digiline_send(jumpdrive.channel, {command = "get"})
else
send_to_monitors("You can't change the radius, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.key_enter_field ~= nil then
if event.msg.key_enter_field == "target" then
mem.jumpdrive.target = coordinates:to_table(event.msg.target)
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "get"})
elseif event.msg.key_enter_field == "jump_step_value" then
table.insert(touchscreen.update_pages, 1, "Jumpdrive")
else send_to_monitors("Unknown key_enter_field: " .. tostring(event.msg.key_enter_field)) end
elseif event.msg.reset_target ~= nil then
digiline_send(jumpdrive.channel, {command = "reset"})
digiline_send(jumpdrive.channel, {command = "get"})
elseif event.msg.set_target ~= nil then
if event.msg.target ~= nil then
mem.jumpdrive.target = coordinates:to_table(event.msg.target)
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "get"})
end
elseif event.msg.request_data ~= nil then
mem.jumpdrive.target = coordinates:to_table(event.msg.target)
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "get"})
elseif event.msg.simulate ~= nil then
mem.jumpdrive.target = coordinates:to_table(event.msg.target)
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "simulate"})
elseif event.msg.jump ~= nil then
if authorised then
mem.jumpdrive.target = coordinates:to_table(event.msg.target)
-- mem.jumpdrive.target = mem.jumpdrive.position
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "jump"})
else
send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.jump_step_increase ~= nil then
local target_jump_step_value = tonumber(event.msg.jump_step_value) + 1
if target_jump_step_value > min_jump_step_value then mem.instant_jump.distance = target_jump_step_value
else mem.instant_jump.distance = min_jump_step_value end
if mem.instant_jump.distance ~= tonumber(event.msg.jump_step_value) then table.insert(touchscreen.update_pages, 1, "Jumpdrive") end
elseif event.msg.jump_step_decrease ~= nil then
local target_jump_step_value = tonumber(event.msg.jump_step_value) - 1
if target_jump_step_value > min_jump_step_value then mem.instant_jump.distance = target_jump_step_value
else mem.instant_jump.distance = min_jump_step_value end
if mem.instant_jump.distance ~= tonumber(event.msg.jump_step_value) then table.insert(touchscreen.update_pages, 1, "Jumpdrive") end
elseif event.msg.xi ~= nil then
if authorised then
-- mem.jumpdrive.target = mem.jumpdrive.position
mem.jumpdrive.target.x = mem.jumpdrive.position.x + mem.instant_jump.distance
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "jump"})
else
send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.xd ~= nil then
if authorised then
-- mem.jumpdrive.target = mem.jumpdrive.position
mem.jumpdrive.target.x = mem.jumpdrive.position.x - mem.instant_jump.distance
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "jump"})
else
send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.yi ~= nil then
if authorised then
-- mem.jumpdrive.target = mem.jumpdrive.position
mem.jumpdrive.target.y = mem.jumpdrive.position.y + mem.instant_jump.distance
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "jump"})
else
send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.yd ~= nil then
if authorised then
-- mem.jumpdrive.target = mem.jumpdrive.position
mem.jumpdrive.target.y = mem.jumpdrive.position.y - mem.instant_jump.distance
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "jump"})
else
send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.zi ~= nil then
if authorised then
-- mem.jumpdrive.target = mem.jumpdrive.position
mem.jumpdrive.target.z = mem.jumpdrive.position.z + mem.instant_jump.distance
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "jump"})
else
send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.zd ~= nil then
if authorised then
-- mem.jumpdrive.target = mem.jumpdrive.position
mem.jumpdrive.target.z = mem.jumpdrive.position.z - mem.instant_jump.distance
digiline_send(jumpdrive.channel, merge_shallow_tables({command = "set", formupdate = false}, mem.jumpdrive.target))
digiline_send(jumpdrive.channel, {command = "jump"})
else
send_to_monitors("You can't jump, " .. tostring(event.msg.clicker) .. " ;)")
end
elseif event.msg.reset_quarries_on_jump ~= nil then
if authorised then
-- mem.reset_quarries_on_jump = event.msg.reset_quarries_on_jump
if event.msg.reset_quarries_on_jump == "true" then mem.reset_quarries_on_jump = true
else mem.reset_quarries_on_jump = false
end
table.insert(touchscreen.update_pages, 1, "Jumpdrive")
else
send_to_monitors("You can't change this, " .. tostring(event.msg.clicker) .. " ;)")
end
end
end
end
-- ########
-- Jumpdrive
-- ########
if mem.jumpdrive == nil then
mem.jumpdrive = {radius = 1, power_req = 0, distance = 0, powerstorage = 0, position = {x=0,y=0,z=0}, target = {x=0,y=0,z=0}, success = false, msg = "", time = 0}
end
if event.type == "program" then digiline_send(jumpdrive.channel, {command = "get"}) end
if event.type == "digiline" and event.channel == jumpdrive.channel and event.msg then
local output = ""
local updated = {}
for k, v in pairs(event.msg) do
if mem.jumpdrive[k] ~= nil then
-- if mem.jumpdrive[k] ~= v then output = output .. " " .. tostring(k) .. ": " .. get_string(mem.jumpdrive[k]) .. " -> " .. get_string(v) end
mem.jumpdrive[k] = v
else
add_line_to_buffer(touchscreen.linebuffer.jumpdrive, "Unknown jumpdrive propperty: " .. get_string(k) .. ":" .. get_string(v))
end
end
if event.msg.success ~= nil then
if event.msg.success == true then
output = output .. " Success!"
if mem.reset_quarries_on_jump then digiline_send(quarries.channel, {command = "set", restart = true}) end
else output = output .. " Failure! (Best refresh and reset)"
end
end
if event.msg.msg then output = output .. " " .. event.msg.msg end
if event.msg.time then
output = output .. " Jumped (" .. tostring(event.msg.time) .. ")"
mem.jumpdrive.position = mem.jumpdrive.target
digiline_send(jumpdrive.channel, {command = "get"})
end
if output ~= nil then
if output ~= "" then add_line_to_buffer(touchscreen.linebuffer.jumpdrive, tostring(mem.events.count) .. ":" .. output) end
else
add_line_to_buffer(touchscreen.linebuffer.jumpdrive, tostring(mem.events.count) .. ":" .. "Output was nil!")
end
table.insert(touchscreen.update_pages, 1, "Jumpdrive")
end
-- ########
-- Event Catcher and update screens
-- ########
if mem.event_catcher == nil then
mem.event_catcher = {touchscreen_line_table = {"Initialized at " .. get_time_string() .. ", " .. _VERSION}}
end
send_to_monitors(event)
for i, page in ipairs(touchscreen.update_pages) do
if page == touchscreen.pages[mem.page] then
update_page(touchscreen.pages[mem.page])
break
end
end
mem.events.count = mem.events.count + 1
--[[
MIT License
Copyright (c) 2021 Florian Finke
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.
]]
Game Controller steered Jumpdrive with Noteblock feedback
--[[
Usage:
- Mount the game controller (Rightclick it)
- Set direction of travel (Look that way)
- Increase jump distance (Hold the jump key and slightly move your mouse [or pushing the forward key])
- Jump (Release the jump button)
Setup:
LUAc with this code attached to:
- Jumpdrive (jumpdrive:engine), digiline channel "jumpdrive" (default)
- Digilines Game Controller (digistuff:controller), digiline channel "gc"
Optional (for feedback):
- Digilines Noteblock (digistuff:noteblock), digiline channel "speaker"
(See the settings to e.g. change the channels)
Jump on ;)
]]
-- Settings
local users = {"singleplayer", "FeXoR", "6r1d", "SX", "SwissalpS", "Huhhila", "BuckarooBanzai", "admin"}
local jumpdrive_channel = "jumpdrive"
local game_controller_channel = "gc"
local note_block_channel = "speaker"
local delay = heat
local sounds = {"c", "d", "e", "f", "g", "a", "b", "c2"}
--local sounds = {"c", "csharp", "d", "dsharp", "e", "f", "fsharp", "g", "gsharp", "a", "asharp", "b", "c2", "csharp2", "d2", "dsharp2", "e2", "f2", "fsharp2", "g2", "gsharp2", "a2", "asharp2", "b2"}
local max_dist = 48
-- Functions
local function permission_check(user)
for i, u in ipairs(users) do
if user == u then
return true
end
end
return false
end
-- Do stuff
if event.type == "program" then
digiline_send(jumpdrive_channel, {command = "get"})
digiline_send(note_block_channel, "get_sounds") -- DEBUG
digiline_send(note_block_channel, "digistuff_piezo_short")
--digiline_send(note_block_channel, "default_place_node_metal")
--digiline_send(note_block_channel, "anvil_clang")
--digiline_send(note_block_channel, "sine")
--digiline_send(note_block_channel, "unified_inventory_refill")
--digiline_send(note_block_channel, "homedecor_toilet")
end
if event.channel == jumpdrive_channel and
type(event.msg) == "table"
then
if type(event.msg.position) == "table" then mem.position = event.msg.position end
-- Set jump distance slightly larger than diagonal extend of jumped area even for radius 1
if type(event.msg.radius) == "number" then mem.min_dist = math.min(4 * event.msg.radius + 2, max_dist) end
if event.msg.success == true then digiline_send(note_block_channel, "technic_laser_mk1") end
if event.msg.success == false then digiline_send(note_block_channel, "technic_laser_mk2") end
end
if event.channel == game_controller_channel then
if event.msg == "player_left" and mem.target == nil then -- Not released pre-jump
mem.power = 0
digiline_send(note_block_channel, "unified_inventory_refill")
elseif
type(event.msg) == "table"
then
if type(event.msg.name) == "string" and permission_check(event.msg.name) == true then
if event.msg.jump == true then
if type(mem.power) == "number" then
mem.power = math.min(mem.power + 1, #sounds)
else
mem.power = 1
end
digiline_send(note_block_channel, sounds[mem.power])
else
if type(mem.power) == "number" and mem.power > 0
then
if type(event.msg.look_vector) == "table" and
type(mem.position) == "table" and type(mem.min_dist) == "number"
then
local distance = mem.min_dist + (max_dist - mem.min_dist) / #sounds * mem.power
mem.target = {
x = math.floor(0.5 + mem.position.x + distance * event.msg.look_vector.x),
y = math.floor(0.5 + mem.position.y + distance * event.msg.look_vector.y),
z = math.floor(0.5 + mem.position.z + distance * event.msg.look_vector.z)
}
digiline_send(game_controller_channel, "release")
interrupt(delay)
else
digiline_send("DEBUG", "Insufficient information to set target!")
end
end
end
else
digiline_send(note_block_channel, "sine") -- Access denied
digiline_send(game_controller_channel, "release")
end
end
end
if event.type == "interrupt" then
if mem.position == nil then
digiline_send(jumpdrive_channel, {command = "get"})
interrupt(delay)
end
if mem.target ~= nil then
digiline_send(jumpdrive_channel, {command = "set", x = mem.target.x, y = mem.target.y, z = mem.target.z})
mem.target = nil
mem.power = 0
mem.position = nil
digiline_send(jumpdrive_channel, {command = "jump"})
interrupt(delay)
end
end
--[[
MIT License
Copyright (c) 2021 Florian Finke
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.
]]
Some calculation about a diamond in 2 orientations for Hedgehog ;)
debug = 0
print("3D Diamond with square layers (less symmetric)")
# Scatch of layer with width 3:
# ooo
# ooo
# ooo
n = 0
for i in range(100):
w = 2*i+1
if debug: print(" Width of layer: " + str(w))
a = w**2
if debug: print(" Nodes for this layer: " + str(a))
n += a
n *= 2
w = 2*100+1
if debug: print(" Central width: "+str(w))
a = w**2
if debug: print(" Nodes for center layer: " + str(a))
n += a
print(" Total number of nodes: " + str(n))
# 2707001
# (2*100+1)**2 + 2 * ((2*0+1)**2 + (2*1+1)**2 + ... + (2*99+1)**2)
# = (2*100+1)**2 + 2 * sum(i=0 to 99)[(2*i+1)**2]
# = (2*100+1)**2 + 2/3*(99+1)*(2*99+1)*(2*99+3)
print(" (Test: " + str((2*100+1)**2 + 2/3*(99+1)*(2*99+1)*(2*99+3)) + " )\n")
print("3D Diamond with non-square layers (more symmetric)")
# Scatch of layer with width 3:
# o
# ooo
# o
n = 0
for i in range(100):
if debug: print(" Width of layer: " + str(2*i+1))
a = (i+1)*(i+2)-1
if debug: print(" Nodes for this layer: " + str(a))
n += a
n *= 2
if debug: print(" Central width: "+str(2*100+1))
a = (100+1)*(100+2)-1
if debug: print(" Nodes for center layer: " + str(a))
n += a
print(" Total number of nodes: " + str(n))
# 696901
# 2 * ((0+1)*(0+2)-1 + (1+1)*(1+2)-1 + ... + (n+1)*(n+2)-1) + (100+1)*(100+2)-1
# = (100+1)*(100+2)-1 + 2* sum(i=0 to 99)[(i+1)*(i+2)-1]
# = (100+1)*(100+2)-1 + 2/3*(99+1)*(99**2+5*99+3)
print(" (Test: " + str((100+1)*(100+2)-1 + 2/3*(99+1)*(99**2+5*99+3)) + " )\n")