From a3966d1a029cbeaaf6778313ee44dd6ada9ed369 Mon Sep 17 00:00:00 2001 From: SX Date: Fri, 14 Feb 2020 02:07:10 +0200 Subject: Refactoring crafts formspecs components helpers --- init.lua | 390 ++++----------------------------------------------------------- 1 file changed, 23 insertions(+), 367 deletions(-) (limited to 'init.lua') diff --git a/init.lua b/init.lua index 905e5e3..b462b5b 100644 --- a/init.lua +++ b/init.lua @@ -1,43 +1,36 @@ --- Initial speed of a box. -local SPEED = 10 --- Acceleration of a box. -local ACCEL = 0.1 --- Elevator interface/database version. -local VERSION = 8 --- Maximum time a box can go without players nearby. -local PTIMEOUT = 120 - -- Detect optional mods. local armor_path = minetest.get_modpath("3d_armor") -- global runtime storage for data and references --- contains .motors loaded from mod storage and api functions +-- contains .motors loaded from mod storage +-- runtime variables and api functions elevator = { + SPEED = 10, -- Initial speed of a box. + ACCEL = 0.1, -- Acceleration of a box. + VISUAL_INCREASE = 1.75, + VERSION = 8, -- Elevator interface/database version. + PTIMEOUT = 120, -- Maximum time a box can go without players nearby. + boxes = {}, -- Elevator boxes in action. lastboxes = {}, -- Player near box timeout. riding = {}, -- Players riding boxes. + formspecs = {}, -- Player formspecs. } local MP = minetest.get_modpath(minetest.get_current_modname()) +dofile(MP .. "/helpers.lua") dofile(MP .. "/storage.lua") -dofile(MP .. "/register.lua") +dofile(MP .. "/crafts.lua") +dofile(MP .. "/components.lua") dofile(MP .. "/hooks.lua") +dofile(MP .. "/formspecs.lua") --- Player formspecs. -local formspecs = {} - --- Helper function to read unloaded nodes. -local function get_node(pos) - local node = minetest.get_node_or_nil(pos) - if node then return node end - local _,_ = VoxelManip():read_from_map(pos, pos) - return minetest.get_node_or_nil(pos) -end - -local VISUAL_INCREASE = 1.75 +local phash = elevator.phash +local punhash = elevator.punhash +local get_node = elevator.get_node -- Cause to ride beginning at and targetting . -local function create_box(motorhash, pos, target, sender) +elevator.create_box = function(motorhash, pos, target, sender) -- First create the box. local obj = minetest.add_entity(pos, "elevator:box") obj:setpos(pos) @@ -45,7 +38,7 @@ local function create_box(motorhash, pos, target, sender) sender:setpos(pos) sender:set_attach(obj, "", {x=0, y=9, z=0}, {x=0, y=0, z=0}) sender:set_eye_offset({x=0, y=-9, z=0},{x=0, y=-9, z=0}) - sender:set_properties({visual_size = {x=VISUAL_INCREASE, y=VISUAL_INCREASE}}) + sender:set_properties({visual_size = {x=elevator.VISUAL_INCREASE, y=elevator.VISUAL_INCREASE}}) if armor_path then armor:update_player_visuals(sender) end @@ -58,8 +51,8 @@ local function create_box(motorhash, pos, target, sender) obj:get_luaentity().halfway = {x=pos.x, y=(pos.y+target.y)/2, z=pos.z} obj:get_luaentity().vmult = (target.y < pos.y) and -1 or 1 -- Set the speed. - obj:setvelocity({x=0, y=SPEED*obj:get_luaentity().vmult, z=0}) - obj:setacceleration({x=0, y=ACCEL*obj:get_luaentity().vmult, z=0}) + obj:setvelocity({x=0, y=elevator.SPEED*obj:get_luaentity().vmult, z=0}) + obj:setacceleration({x=0, y=elevator.ACCEL*obj:get_luaentity().vmult, z=0}) -- Set the tables. elevator.boxes[motorhash] = obj elevator.riding[sender:get_player_name()] = { @@ -71,36 +64,6 @@ local function create_box(motorhash, pos, target, sender) return obj end --- Try to teleport player away from any closed (on) elevator node. -elevator.teleport_player_from_elevator = function(player) - local function solid(pos) - if not minetest.registered_nodes[minetest.get_node(pos).name] then - return true - end - return minetest.registered_nodes[minetest.get_node(pos).name].walkable - end - local pos = vector.round(player:getpos()) - local node = minetest.get_node(pos) - -- elevator_off is like a shaft, so the player would already be falling. - if node.name == "elevator:elevator_on" then - local front = vector.subtract(pos, minetest.facedir_to_dir(node.param2)) - local front_above = vector.add(front, {x=0, y=1, z=0}) - local front_below = vector.subtract(front, {x=0, y=1, z=0}) - -- If the front isn't solid, it's ok to teleport the player. - if not solid(front) and not solid(front_above) then - player:setpos(front) - end - end -end - -local function phash(pos) - return minetest.pos_to_string(pos) -end - -local function punhash(pos) - return minetest.string_to_pos(pos) -end - -- Starting from , locate a motor hash. elevator.locate_motor = function(pos) local p = vector.new(pos) @@ -158,7 +121,7 @@ elevator.build_motor = function(hash) for i,m in ipairs(motor.elevators) do local pos = punhash(m) local meta = minetest.get_meta(pos) - meta:set_int("version", VERSION) + meta:set_int("version", elevator.VERSION) if meta:get_string("motor") ~= hash then elevator.build_motor(meta:get_string("motor")) end @@ -213,319 +176,12 @@ elevator.unbuild = function(pos, add) end, table.copy(pos), add) end -minetest.register_node("elevator:motor", { - description = "Elevator Motor", - tiles = { - "default_steel_block.png", - "default_steel_block.png", - "elevator_motor.png", - "elevator_motor.png", - "elevator_motor.png", - "elevator_motor.png", - }, - groups = {cracky=1}, - sounds = default.node_sound_stone_defaults(), - after_place_node = function(pos, placer, itemstack) - -- Set up the motor table. - elevator.motors[phash(pos)] = { - elevators = {}, - pnames = {}, - labels = {}, - } - elevator.save_elevator() - elevator.build_motor(phash(pos)) - end, - on_destruct = function(pos) - -- Destroy everything related to this motor. - elevator.boxes[phash(pos)] = nil - elevator.motors[phash(pos)] = nil - elevator.save_elevator() - end, -}) - -for _,mode in ipairs({"on", "off"}) do - local nodename = "elevator:elevator_"..mode - local on = (mode == "on") - local box - local cbox - if on then - -- Active elevators have a ceiling and floor. - box = { - - { 0.48, -0.5,-0.5, 0.5, 1.5, 0.5}, - {-0.5 , -0.5, 0.48, 0.48, 1.5, 0.5}, - {-0.5, -0.5,-0.5 ,-0.48, 1.5, 0.5}, - - { -0.5,-0.5,-0.5,0.5,-0.48, 0.5}, - { -0.5, 1.45,-0.5,0.5, 1.5, 0.5}, - } - cbox = table.copy(box) - -- But you can enter them from the top. - cbox[5] = nil - else - -- Inactive elevators are almost like shafts. - box = { - - { 0.48, -0.5,-0.5, 0.5, 1.5, 0.5}, - {-0.5 , -0.5, 0.48, 0.48, 1.5, 0.5}, - {-0.5, -0.5,-0.5 ,-0.48, 1.5, 0.5}, - {-0.5 , -0.5, -0.48, 0.5, 1.5, -0.5}, - } - cbox = box - end - minetest.register_node(nodename, { - description = "Elevator", - drawtype = "nodebox", - sunlight_propagates = false, - paramtype = "light", - paramtype2 = "facedir", - on_rotate = screwdriver.disallow, - - selection_box = { - type = "fixed", - fixed = box, - }, - - collision_box = { - type = "fixed", - fixed = cbox, - }, - - node_box = { - type = "fixed", - fixed = box, - }, - - tiles = on and { - "default_steel_block.png", - "default_steel_block.png", - "elevator_box.png", - "elevator_box.png", - "elevator_box.png", - "elevator_box.png", - } or { - "elevator_box.png", - "elevator_box.png", - "elevator_box.png", - "elevator_box.png", - "elevator_box.png", - "elevator_box.png", - }, - groups = {cracky=1, choppy=1, snappy=1}, - drop = "elevator:elevator_off", - - -- Emit a bit of light when active. - light_source = (on and 4 or nil), - - after_place_node = function(pos, placer, itemstack) - local meta = minetest.get_meta(pos) - meta:set_int("version", VERSION) - - -- Add a placeholder to avoid nodes being placed in the top. - local p = vector.add(pos, {x=0, y=1, z=0}) - local p2 = minetest.dir_to_facedir(placer:get_look_dir()) - minetest.set_node(p, {name="elevator:placeholder", paramtype2="facedir", param2=p2}) - - -- Try to build a motor above. - local motor = elevator.locate_motor(pos) - if motor then - elevator.build_motor(motor) - end - end, - - after_dig_node = function(pos, node, meta, digger) - elevator.unbuild(pos, 2) - end, - - on_place = function(itemstack, placer, pointed_thing) - local pos = pointed_thing.above - local node = minetest.get_node(vector.add(pos, {x=0, y=1, z=0})) - if (node ~= nil and node.name ~= "air" and node.name ~= "elevator:placeholder") then - return - end - return minetest.item_place(itemstack, placer, pointed_thing) - end, - - on_rightclick = function(pos, node, sender) - if not sender or not sender:is_player() then - return - end - local formspec - local meta = minetest.get_meta(pos) - formspecs[sender:get_player_name()] = {pos} - if on then - if vector.distance(sender:getpos(), pos) > 1 or minetest.get_node(sender:getpos()).name ~= nodename then - minetest.chat_send_player(sender:get_player_name(), "You are not inside the booth.") - return - end - -- Build the formspec from the motor table. - local tpnames = {} - local tpnames_l = {} - local motorhash = meta:get_string("motor") - local motor = elevator.motors[motorhash] - for ji,jv in ipairs(motor.pnames) do - if tonumber(jv) ~= pos.y then - table.insert(tpnames, jv) - table.insert(tpnames_l, (motor.labels[ji] and motor.labels[ji] ~= "") and (jv.." - "..minetest.formspec_escape(motor.labels[ji])) or jv) - end - end - formspecs[sender:get_player_name()] = {pos, tpnames} - if #tpnames > 0 then - if not minetest.is_protected(pos, sender:get_player_name()) then - formspec = "size[4,6]" - .."label[0,0;Click once to travel.]" - .."textlist[-0.1,0.5;4,4;target;"..table.concat(tpnames_l, ",").."]" - .."field[0.25,5.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" - .."button_exit[-0.05,5.5;4,1;setlabel;Set label]" - else - formspec = "size[4,4.4]" - .."label[0,0;Click once to travel.]" - .."textlist[-0.1,0.5;4,4;target;"..table.concat(tpnames_l, ",").."]" - end - else - if not minetest.is_protected(pos, sender:get_player_name()) then - formspec = "size[4,2]" - .."label[0,0;No targets available.]" - .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" - .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" - else - formspec = "size[4,0.4]" - .."label[0,0;No targets available.]" - end - end - minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) - elseif not elevator.motors[meta:get_string("motor")] then - if not minetest.is_protected(pos, sender:get_player_name()) then - formspec = "size[4,2]" - .."label[0,0;This elevator is inactive.]" - .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" - .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" - else - formspec = "size[4,0.4]" - .."label[0,0;This elevator is inactive.]" - end - minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) - elseif elevator.boxes[meta:get_string("motor")] then - if not minetest.is_protected(pos, sender:get_player_name()) then - formspec = "size[4,2]" - .."label[0,0;This elevator is in use.]" - .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" - .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" - else - formspec = "size[4,0.4]" - .."label[0,0;This elevator is in use.]" - end - minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) - end - end, - - on_destruct = function(pos) - local p = vector.add(pos, {x=0, y=1, z=0}) - if get_node(p).name == "elevator:placeholder" then - minetest.remove_node(p) - end - end, - }) -end - -minetest.register_on_player_receive_fields(function(sender, formname, fields) - if formname ~= "elevator:elevator" then - return - end - local pos = formspecs[sender:get_player_name()] and formspecs[sender:get_player_name()][1] or nil - if not pos then - return true - end - local meta = minetest.get_meta(pos) - if fields.setlabel then - if minetest.is_protected(pos, sender:get_player_name()) then - return true - end - meta:set_string("label", fields.label) - meta:set_string("infotext", fields.label) - -- Rebuild the elevator shaft so the other elevators can read this label. - local motorhash = meta:get_string("motor") - elevator.build_motor(elevator.motors[motorhash] and motorhash or elevator.locate_motor(pos)) - return true - end - -- Double check if it's ok to go. - if vector.distance(sender:getpos(), pos) > 1 then - return true - end - if fields.target then - local closeformspec = "" - -- HACK: With player information extensions enabled, we can check if closing formspecs are now allowed. This is specifically used on Survival in Ethereal. - local pi = minetest.get_player_information(sender:get_player_name()) - if (not (pi.major == 0 and pi.minor == 4 and pi.patch == 15)) and (pi.protocol_version or 29) < 29 then - closeformspec = "size[4,2] label[0,0;You are now using the elevator.\nUpgrade Minetest to avoid this dialog.] button_exit[0,1;4,1;close;Close]" - end - -- End hacky HACK. - minetest.after(0.2, minetest.show_formspec, sender:get_player_name(), "elevator:elevator", closeformspec) - -- Ensure we're connected to a motor. - local motorhash = meta:get_string("motor") - local motor = elevator.motors[motorhash] - if not motor then - motorhash = elevator.locate_motor(pos) - motor = elevator.motors[motorhash] - if motor then - meta:set_string("motor", "") - elevator.build_motor(motorhash) - minetest.chat_send_player(sender:get_player_name(), "Recalibrated to a new motor, please try again.") - return true - end - end - if not motor then - minetest.chat_send_player(sender:get_player_name(), "This elevator is not attached to a motor.") - return true - end - if not formspecs[sender:get_player_name()][2] or not formspecs[sender:get_player_name()][2][minetest.explode_textlist_event(fields.target).index] then - return true - end - -- Locate our target elevator. - local target = nil - local selected_target = formspecs[sender:get_player_name()][2][minetest.explode_textlist_event(fields.target).index] - for i,v in ipairs(motor.pnames) do - if v == selected_target then - target = punhash(motor.elevators[i]) - end - end - -- Found the elevator? Then go! - if target then - -- Final check. - if elevator.boxes[motorhash] then - minetest.chat_send_player(sender:get_player_name(), "This elevator is in use.") - return true - end - local obj = create_box(motorhash, pos, target, sender) - -- Teleport anyone standing within an on elevator out, or they'd fall through the off elevators. - for _,p in ipairs(motor.elevators) do - local p = punhash(p) - for _,object in ipairs(minetest.get_objects_inside_radius(p, 0.6)) do - if object.is_player and object:is_player() then - if object:get_player_name() ~= obj:get_luaentity().attached then - elevator.teleport_player_from_elevator(object) - end - end - end - end - else - minetest.chat_send_player(sender:get_player_name(), "This target is invalid.") - return true - end - return true - end - return true -end) - --- Compatability with an older version. -minetest.register_alias("elevator:elevator", "elevator:elevator_off") - -- Ensure an elevator is up to the latest version. local function upgrade_elevator(pos, meta) - if meta:get_int("version") ~= VERSION then + if meta:get_int("version") ~= elevator.VERSION then minetest.log("action", "[elevator] Updating elevator with old version at "..minetest.pos_to_string(pos)) minetest.after(0, function(pos) elevator.build_motor(elevator.locate_motor(pos)) end, pos) - meta:set_int("version", VERSION) + meta:set_int("version", elevator.VERSION) meta:set_string("formspec", "") meta:set_string("infotext", meta:get_string("label")) end -- cgit v1.2.3